123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984 |
- .. _ref-contrib-syndication:
- ==============================
- The syndication feed framework
- ==============================
- .. module:: django.contrib.syndication
- :synopsis: A framework for generating syndication feeds, in RSS and Atom,
- quite easily.
- Django comes with a high-level syndication-feed-generating framework that makes
- creating RSS_ and Atom_ feeds easy.
- To create any syndication feed, all you have to do is write a short Python
- class. You can create as many feeds as you want.
- Django also comes with a lower-level feed-generating API. Use this if you want
- to generate feeds outside of a Web context, or in some other lower-level way.
- .. _RSS: http://www.whatisrss.com/
- .. _Atom: http://www.atomenabled.org/
- The high-level framework
- ========================
- Overview
- --------
- The high-level feed-generating framework is a view that's hooked to ``/feeds/``
- by default. Django uses the remainder of the URL (everything after ``/feeds/``)
- to determine which feed to output.
- To create a feed, just write a :class:`~django.contrib.syndication.feeds.Feed`
- class and point to it in your :ref:`URLconf <topics-http-urls>`.
- Initialization
- --------------
- To activate syndication feeds on your Django site, add this line to your
- :ref:`URLconf <topics-http-urls>`::
- (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}),
- This tells Django to use the RSS framework to handle all URLs starting with
- :file:`"feeds/"`. (You can change that :file:`"feeds/"` prefix to fit your own
- needs.)
- This URLconf line has an extra argument: ``{'feed_dict': feeds}``. Use this
- extra argument to pass the syndication framework the feeds that should be
- published under that URL.
- Specifically, :data:`feed_dict` should be a dictionary that maps a feed's slug
- (short URL label) to its :class:`~django.contrib.syndication.feeds.Feed` class.
- You can define the ``feed_dict`` in the URLconf itself. Here's a full example
- URLconf::
- from django.conf.urls.defaults import *
- from myproject.feeds import LatestEntries, LatestEntriesByCategory
- feeds = {
- 'latest': LatestEntries,
- 'categories': LatestEntriesByCategory,
- }
- urlpatterns = patterns('',
- # ...
- (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
- {'feed_dict': feeds}),
- # ...
- )
- The above example registers two feeds:
- * The feed represented by ``LatestEntries`` will live at ``feeds/latest/``.
- * The feed represented by ``LatestEntriesByCategory`` will live at
- ``feeds/categories/``.
- Once that's set up, you just need to define the
- :class:`~django.contrib.syndication.feeds.Feed` classes themselves.
- Feed classes
- ------------
- A :class:`~django.contrib.syndication.feeds.Feed` class is a simple Python class
- that represents a syndication feed. A feed can be simple (e.g., a "site news"
- feed, or a basic feed displaying the latest entries of a blog) or more complex
- (e.g., a feed displaying all the blog entries in a particular category, where
- the category is variable).
- :class:`~django.contrib.syndication.feeds.Feed` classes must subclass
- ``django.contrib.syndication.feeds.Feed``. They can live anywhere in your
- codebase.
- A simple example
- ----------------
- This simple example, taken from `chicagocrime.org`_, describes a feed of the
- latest five news items::
- from django.contrib.syndication.feeds import Feed
- from chicagocrime.models import NewsItem
- class LatestEntries(Feed):
- title = "Chicagocrime.org site news"
- link = "/sitenews/"
- description = "Updates on changes and additions to chicagocrime.org."
- def items(self):
- return NewsItem.objects.order_by('-pub_date')[:5]
- Note:
- * The class subclasses ``django.contrib.syndication.feeds.Feed``.
- * :attr:`title`, :attr:`link` and :attr:`description` correspond to the
- standard RSS ``<title>``, ``<link>`` and ``<description>`` elements,
- respectively.
- * :meth:`items()` is, simply, a method that returns a list of objects that
- should be included in the feed as ``<item>`` elements. Although this
- example returns ``NewsItem`` objects using Django's
- :ref:`object-relational mapper <ref-models-querysets>`, :meth:`items()`
- doesn't have to return model instances. Although you get a few bits of
- functionality "for free" by using Django models, :meth:`items()` can
- return any type of object you want.
- * If you're creating an Atom feed, rather than an RSS feed, set the
- :attr:`subtitle` attribute instead of the :attr:`description` attribute.
- See `Publishing Atom and RSS feeds in tandem`_, later, for an example.
- One thing's left to do. In an RSS feed, each ``<item>`` has a ``<title>``,
- ``<link>`` and ``<description>``. We need to tell the framework what data to put
- into those elements.
- * To specify the contents of ``<title>`` and ``<description>``, create
- :ref:`Django templates <topics-templates>` called
- :file:`feeds/latest_title.html` and
- :file:`feeds/latest_description.html`, where :attr:`latest` is the
- :attr:`slug` specified in the URLconf for the given feed. Note the
- ``.html`` extension is required. The RSS system renders that template for
- each item, passing it two template context variables:
- * ``{{ obj }}`` -- The current object (one of whichever objects you
- returned in :meth:`items()`).
-
- * ``{{ site }}`` -- A :class:`django.contrib.sites.models.Site` object
- representing the current site. This is useful for ``{{ site.domain
- }}`` or ``{{ site.name }}``. If you do *not* have the Django sites
- framework installed, this will be set to a
- :class:`django.contrib.sites.models.RequestSite` object. See the
- :ref:`RequestSite section of the sites framework documentation
- <requestsite-objects>` for more.
- If you don't create a template for either the title or description, the
- framework will use the template ``"{{ obj }}"`` by default -- that is, the
- normal string representation of the object. You can also change the names
- of these two templates by specifying ``title_template`` and
- ``description_template`` as attributes of your
- :class:`~django.contrib.syndication.feeds.Feed` class.
- * To specify the contents of ``<link>``, you have two options. For each item
- in :meth:`items()`, Django first tries executing a ``get_absolute_url()``
- method on that object. If that method doesn't exist, it tries calling a
- method :meth:`item_link()` in the
- :class:`~django.contrib.syndication.feeds.Feed` class, passing it a single
- parameter, :attr:`item`, which is the object itself. Both
- ``get_absolute_url()`` and :meth:`item_link()` should return the item's
- URL as a normal Python string. As with ``get_absolute_url()``, the result
- of :meth:`item_link()` will be included directly in the URL, so you are
- responsible for doing all necessary URL quoting and conversion to ASCII
- inside the method itself.
- * For the LatestEntries example above, we could have very simple feed
- templates:
- * latest_title.html:
- .. code-block:: html+django
- {{ obj.title }}
- * latest_description.html:
-
- .. code-block:: html+django
-
- {{ obj.description }}
- .. _chicagocrime.org: http://www.chicagocrime.org/
- A complex example
- -----------------
- The framework also supports more complex feeds, via parameters.
- For example, `chicagocrime.org`_ offers an RSS feed of recent crimes for every
- police beat in Chicago. It'd be silly to create a separate
- :class:`~django.contrib.syndication.feeds.Feed` class for each police beat; that
- would violate the :ref:`DRY principle <dry>` and would couple data to
- programming logic. Instead, the syndication framework lets you make generic
- feeds that output items based on information in the feed's URL.
- On chicagocrime.org, the police-beat feeds are accessible via URLs like this:
- * :file:`/rss/beats/0613/` -- Returns recent crimes for beat 0613.
- * :file:`/rss/beats/1424/` -- Returns recent crimes for beat 1424.
- The slug here is ``"beats"``. The syndication framework sees the extra URL bits
- after the slug -- ``0613`` and ``1424`` -- and gives you a hook to tell it what
- those URL bits mean, and how they should influence which items get published in
- the feed.
- An example makes this clear. Here's the code for these beat-specific feeds::
- from django.contrib.syndication.feeds import FeedDoesNotExist
- class BeatFeed(Feed):
- def get_object(self, bits):
- # In case of "/rss/beats/0613/foo/bar/baz/", or other such clutter,
- # check that bits has only one member.
- if len(bits) != 1:
- raise ObjectDoesNotExist
- return Beat.objects.get(beat__exact=bits[0])
- def title(self, obj):
- return "Chicagocrime.org: Crimes for beat %s" % obj.beat
- def link(self, obj):
- if not obj:
- raise FeedDoesNotExist
- return obj.get_absolute_url()
- def description(self, obj):
- return "Crimes recently reported in police beat %s" % obj.beat
- def items(self, obj):
- return Crime.objects.filter(beat__id__exact=obj.id).order_by('-crime_date')[:30]
- Here's the basic algorithm the RSS framework follows, given this class and a
- request to the URL :file:`/rss/beats/0613/`:
- * The framework gets the URL :file:`/rss/beats/0613/` and notices there's an
- extra bit of URL after the slug. It splits that remaining string by the
- slash character (``"/"``) and calls the
- :class:`~django.contrib.syndication.feeds.Feed` class'
- :meth:`get_object()` method, passing it the bits. In this case, bits is
- ``['0613']``. For a request to :file:`/rss/beats/0613/foo/bar/`, bits
- would be ``['0613', 'foo', 'bar']``.
- * :meth:`get_object()` is responsible for retrieving the given beat, from
- the given ``bits``. In this case, it uses the Django database API to
- retrieve the beat. Note that :meth:`get_object()` should raise
- :exc:`django.core.exceptions.ObjectDoesNotExist` if given invalid
- parameters. There's no ``try``/``except`` around the
- ``Beat.objects.get()`` call, because it's not necessary; that function
- raises :exc:`Beat.DoesNotExist` on failure, and :exc:`Beat.DoesNotExist`
- is a subclass of :exc:`ObjectDoesNotExist`. Raising
- :exc:`ObjectDoesNotExist` in :meth:`get_object()` tells Django to produce
- a 404 error for that request.
- .. versionadded:: 1.0
- meth:`get_object()` can handle the :file:`/rss/beats/` url.
- The :meth:`get_object()` method also has a chance to handle the
- :file:`/rss/beats/` url. In this case, :data:`bits` will be an
- empty list. In our example, ``len(bits) != 1`` and an
- :exc:`ObjectDoesNotExist` exception will be raised, so
- :file:`/rss/beats/` will generate a 404 page. But you can handle this case
- however you like. For example, you could generate a combined feed for all
- beats.
- * To generate the feed's ``<title>``, ``<link>`` and ``<description>``,
- Django uses the :meth:`title()`, :meth:`link()` and :meth:`description()`
- methods. In the previous example, they were simple string class
- attributes, but this example illustrates that they can be either strings
- *or* methods. For each of :attr:`title`, :attr:`link` and
- :attr:`description`, Django follows this algorithm:
- * First, it tries to call a method, passing the ``obj`` argument, where
- ``obj`` is the object returned by :meth:`get_object()`.
-
- * Failing that, it tries to call a method with no arguments.
-
- * Failing that, it uses the class attribute.
- Inside the :meth:`link()` method, we handle the possibility that ``obj``
- might be ``None``, which can occur when the URL isn't fully specified. In
- some cases, you might want to do something else in this case, which would
- mean you'd need to check for ``obj`` existing in other methods as well.
- (The :meth:`link()` method is called very early in the feed generation
- process, so it's a good place to bail out early.)
- * Finally, note that :meth:`items()` in this example also takes the ``obj``
- argument. The algorithm for :attr:`items` is the same as described in the
- previous step -- first, it tries :meth:`items(obj)`, then :meth:`items()`,
- then finally an :attr:`items` class attribute (which should be a list).
- The ``ExampleFeed`` class below gives full documentation on methods and
- attributes of :class:`~django.contrib.syndication.feeds.Feed` classes.
- Specifying the type of feed
- ---------------------------
- By default, feeds produced in this framework use RSS 2.0.
- To change that, add a ``feed_type`` attribute to your
- :class:`~django.contrib.syndication.feeds.Feed` class, like so::
- from django.utils.feedgenerator import Atom1Feed
- class MyFeed(Feed):
- feed_type = Atom1Feed
- Note that you set ``feed_type`` to a class object, not an instance.
- Currently available feed types are:
- * :class:`django.utils.feedgenerator.Rss201rev2Feed` (RSS 2.01. Default.)
- * :class:`django.utils.feedgenerator.RssUserland091Feed` (RSS 0.91.)
- * :class:`django.utils.feedgenerator.Atom1Feed` (Atom 1.0.)
- Enclosures
- ----------
- To specify enclosures, such as those used in creating podcast feeds, use the
- :attr:`item_enclosure_url`, :attr:`item_enclosure_length` and
- :attr:`item_enclosure_mime_type` hooks. See the ``ExampleFeed`` class below for
- usage examples.
- Language
- --------
- Feeds created by the syndication framework automatically include the
- appropriate ``<language>`` tag (RSS 2.0) or ``xml:lang`` attribute (Atom). This
- comes directly from your :setting:`LANGUAGE_CODE setting`.
- URLs
- ----
- The :attr:`link` method/attribute can return either an absolute URL (e.g.
- :file:`"/blog/"`) or a URL with the fully-qualified domain and protocol (e.g.
- ``"http://www.example.com/blog/"``). If :attr:`link` doesn't return the domain,
- the syndication framework will insert the domain of the current site, according
- to your :setting:`SITE_ID setting <SITE_ID>`.
- Atom feeds require a ``<link rel="self">`` that defines the feed's current
- location. The syndication framework populates this automatically, using the
- domain of the current site according to the :setting:`SITE_ID` setting.
- Publishing Atom and RSS feeds in tandem
- ---------------------------------------
- Some developers like to make available both Atom *and* RSS versions of their
- feeds. That's easy to do with Django: Just create a subclass of your
- :class:`~django.contrib.syndication.feeds.Feed`
- class and set the :attr:`feed_type` to something different. Then update your
- URLconf to add the extra versions.
- Here's a full example::
- from django.contrib.syndication.feeds import Feed
- from chicagocrime.models import NewsItem
- from django.utils.feedgenerator import Atom1Feed
- class RssSiteNewsFeed(Feed):
- title = "Chicagocrime.org site news"
- link = "/sitenews/"
- description = "Updates on changes and additions to chicagocrime.org."
- def items(self):
- return NewsItem.objects.order_by('-pub_date')[:5]
- class AtomSiteNewsFeed(RssSiteNewsFeed):
- feed_type = Atom1Feed
- subtitle = RssSiteNewsFeed.description
- .. Note::
- In this example, the RSS feed uses a :attr:`description` while the Atom
- feed uses a :attr:`subtitle`. That's because Atom feeds don't provide for
- a feed-level "description," but they *do* provide for a "subtitle."
- If you provide a :attr:`description` in your
- :class:`~django.contrib.syndication.feeds.Feed` class, Django will *not*
- automatically put that into the :attr:`subtitle` element, because a
- subtitle and description are not necessarily the same thing. Instead, you
- should define a :attr:`subtitle` attribute.
- In the above example, we simply set the Atom feed's :attr:`subtitle` to the
- RSS feed's :attr:`description`, because it's quite short already.
- And the accompanying URLconf::
- from django.conf.urls.defaults import *
- from myproject.feeds import RssSiteNewsFeed, AtomSiteNewsFeed
- feeds = {
- 'rss': RssSiteNewsFeed,
- 'atom': AtomSiteNewsFeed,
- }
- urlpatterns = patterns('',
- # ...
- (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
- {'feed_dict': feeds}),
- # ...
- )
- Feed class reference
- --------------------
- .. class:: django.contrib.syndication.feeds.Feed
- This example illustrates all possible attributes and methods for a
- :class:`~django.contrib.syndication.feeds.Feed` class::
- from django.contrib.syndication.feeds import Feed
- from django.utils import feedgenerator
- class ExampleFeed(Feed):
- # FEED TYPE -- Optional. This should be a class that subclasses
- # django.utils.feedgenerator.SyndicationFeed. This designates which
- # type of feed this should be: RSS 2.0, Atom 1.0, etc.
- # If you don't specify feed_type, your feed will be RSS 2.0.
- # This should be a class, not an instance of the class.
- feed_type = feedgenerator.Rss201rev2Feed
- # TEMPLATE NAMES -- Optional. These should be strings representing
- # names of Django templates that the system should use in rendering the
- # title and description of your feed items. Both are optional.
- # If you don't specify one, or either, Django will use the template
- # 'feeds/SLUG_title.html' and 'feeds/SLUG_description.html', where SLUG
- # is the slug you specify in the URL.
- title_template = None
- description_template = None
- # TITLE -- One of the following three is required. The framework looks
- # for them in this order.
- def title(self, obj):
- """
- Takes the object returned by get_object() and returns the feed's
- title as a normal Python string.
- """
- def title(self):
- """
- Returns the feed's title as a normal Python string.
- """
- title = 'foo' # Hard-coded title.
- # LINK -- One of the following three is required. The framework looks
- # for them in this order.
- def link(self, obj):
- """
- Takes the object returned by get_object() and returns the feed's
- link as a normal Python string.
- """
- def link(self):
- """
- Returns the feed's link as a normal Python string.
- """
- link = '/foo/bar/' # Hard-coded link.
- # GUID -- One of the following three is optional. The framework looks
- # for them in this order. This property is only used for Atom feeds
- # (where it is the feed-level ID element). If not provided, the feed
- # link is used as the ID.
- def feed_guid(self, obj):
- """
- Takes the object returned by get_object() and returns the globally
- unique ID for the feed as a normal Python string.
- """
- def feed_guid(self):
- """
- Returns the feed's globally unique ID as a normal Python string.
- """
- feed_guid = '/foo/bar/1234' # Hard-coded guid.
- # DESCRIPTION -- One of the following three is required. The framework
- # looks for them in this order.
- def description(self, obj):
- """
- Takes the object returned by get_object() and returns the feed's
- description as a normal Python string.
- """
- def description(self):
- """
- Returns the feed's description as a normal Python string.
- """
- description = 'Foo bar baz.' # Hard-coded description.
- # AUTHOR NAME --One of the following three is optional. The framework
- # looks for them in this order.
- def author_name(self, obj):
- """
- Takes the object returned by get_object() and returns the feed's
- author's name as a normal Python string.
- """
- def author_name(self):
- """
- Returns the feed's author's name as a normal Python string.
- """
- author_name = 'Sally Smith' # Hard-coded author name.
- # AUTHOR E-MAIL --One of the following three is optional. The framework
- # looks for them in this order.
- def author_email(self, obj):
- """
- Takes the object returned by get_object() and returns the feed's
- author's e-mail as a normal Python string.
- """
- def author_email(self):
- """
- Returns the feed's author's e-mail as a normal Python string.
- """
- author_email = 'test@example.com' # Hard-coded author e-mail.
- # AUTHOR LINK --One of the following three is optional. The framework
- # looks for them in this order. In each case, the URL should include
- # the "http://" and domain name.
- def author_link(self, obj):
- """
- Takes the object returned by get_object() and returns the feed's
- author's URL as a normal Python string.
- """
- def author_link(self):
- """
- Returns the feed's author's URL as a normal Python string.
- """
- author_link = 'http://www.example.com/' # Hard-coded author URL.
- # CATEGORIES -- One of the following three is optional. The framework
- # looks for them in this order. In each case, the method/attribute
- # should return an iterable object that returns strings.
- def categories(self, obj):
- """
- Takes the object returned by get_object() and returns the feed's
- categories as iterable over strings.
- """
- def categories(self):
- """
- Returns the feed's categories as iterable over strings.
- """
- categories = ("python", "django") # Hard-coded list of categories.
- # COPYRIGHT NOTICE -- One of the following three is optional. The
- # framework looks for them in this order.
- def copyright(self, obj):
- """
- Takes the object returned by get_object() and returns the feed's
- copyright notice as a normal Python string.
- """
- def copyright(self):
- """
- Returns the feed's copyright notice as a normal Python string.
- """
- copyright = 'Copyright (c) 2007, Sally Smith' # Hard-coded copyright notice.
- # TTL -- One of the following three is optional. The framework looks
- # for them in this order. Ignored for Atom feeds.
- def ttl(self, obj):
- """
- Takes the object returned by get_object() and returns the feed's
- TTL (Time To Live) as a normal Python string.
- """
- def ttl(self):
- """
- Returns the feed's TTL as a normal Python string.
- """
- ttl = 600 # Hard-coded Time To Live.
- # ITEMS -- One of the following three is required. The framework looks
- # for them in this order.
- def items(self, obj):
- """
- Takes the object returned by get_object() and returns a list of
- items to publish in this feed.
- """
- def items(self):
- """
- Returns a list of items to publish in this feed.
- """
- items = ('Item 1', 'Item 2') # Hard-coded items.
- # GET_OBJECT -- This is required for feeds that publish different data
- # for different URL parameters. (See "A complex example" above.)
- def get_object(self, bits):
- """
- Takes a list of strings gleaned from the URL and returns an object
- represented by this feed. Raises
- django.core.exceptions.ObjectDoesNotExist on error.
- """
- # ITEM LINK -- One of these three is required. The framework looks for
- # them in this order.
- # First, the framework tries the two methods below, in
- # order. Failing that, it falls back to the get_absolute_url()
- # method on each item returned by items().
- def item_link(self, item):
- """
- Takes an item, as returned by items(), and returns the item's URL.
- """
- def item_link(self):
- """
- Returns the URL for every item in the feed.
- """
- # ITEM_GUID -- The following method is optional. This property is
- # only used for Atom feeds (it is the ID element for an item in an
- # Atom feed). If not provided, the item's link is used by default.
- def item_guid(self, obj):
- """
- Takes an item, as return by items(), and returns the item's ID.
- """
- # ITEM AUTHOR NAME -- One of the following three is optional. The
- # framework looks for them in this order.
- def item_author_name(self, item):
- """
- Takes an item, as returned by items(), and returns the item's
- author's name as a normal Python string.
- """
- def item_author_name(self):
- """
- Returns the author name for every item in the feed.
- """
- item_author_name = 'Sally Smith' # Hard-coded author name.
- # ITEM AUTHOR E-MAIL --One of the following three is optional. The
- # framework looks for them in this order.
- #
- # If you specify this, you must specify item_author_name.
- def item_author_email(self, obj):
- """
- Takes an item, as returned by items(), and returns the item's
- author's e-mail as a normal Python string.
- """
- def item_author_email(self):
- """
- Returns the author e-mail for every item in the feed.
- """
- item_author_email = 'test@example.com' # Hard-coded author e-mail.
- # ITEM AUTHOR LINK --One of the following three is optional. The
- # framework looks for them in this order. In each case, the URL should
- # include the "http://" and domain name.
- #
- # If you specify this, you must specify item_author_name.
- def item_author_link(self, obj):
- """
- Takes an item, as returned by items(), and returns the item's
- author's URL as a normal Python string.
- """
- def item_author_link(self):
- """
- Returns the author URL for every item in the feed.
- """
- item_author_link = 'http://www.example.com/' # Hard-coded author URL.
- # ITEM ENCLOSURE URL -- One of these three is required if you're
- # publishing enclosures. The framework looks for them in this order.
- def item_enclosure_url(self, item):
- """
- Takes an item, as returned by items(), and returns the item's
- enclosure URL.
- """
- def item_enclosure_url(self):
- """
- Returns the enclosure URL for every item in the feed.
- """
- item_enclosure_url = "/foo/bar.mp3" # Hard-coded enclosure link.
- # ITEM ENCLOSURE LENGTH -- One of these three is required if you're
- # publishing enclosures. The framework looks for them in this order.
- # In each case, the returned value should be either an integer, or a
- # string representation of the integer, in bytes.
- def item_enclosure_length(self, item):
- """
- Takes an item, as returned by items(), and returns the item's
- enclosure length.
- """
- def item_enclosure_length(self):
- """
- Returns the enclosure length for every item in the feed.
- """
- item_enclosure_length = 32000 # Hard-coded enclosure length.
- # ITEM ENCLOSURE MIME TYPE -- One of these three is required if you're
- # publishing enclosures. The framework looks for them in this order.
- def item_enclosure_mime_type(self, item):
- """
- Takes an item, as returned by items(), and returns the item's
- enclosure MIME type.
- """
- def item_enclosure_mime_type(self):
- """
- Returns the enclosure MIME type for every item in the feed.
- """
- item_enclosure_mime_type = "audio/mpeg" # Hard-coded enclosure MIME type.
- # ITEM PUBDATE -- It's optional to use one of these three. This is a
- # hook that specifies how to get the pubdate for a given item.
- # In each case, the method/attribute should return a Python
- # datetime.datetime object.
- def item_pubdate(self, item):
- """
- Takes an item, as returned by items(), and returns the item's
- pubdate.
- """
- def item_pubdate(self):
- """
- Returns the pubdate for every item in the feed.
- """
- item_pubdate = datetime.datetime(2005, 5, 3) # Hard-coded pubdate.
- # ITEM CATEGORIES -- It's optional to use one of these three. This is
- # a hook that specifies how to get the list of categories for a given
- # item. In each case, the method/attribute should return an iterable
- # object that returns strings.
- def item_categories(self, item):
- """
- Takes an item, as returned by items(), and returns the item's
- categories.
- """
- def item_categories(self):
- """
- Returns the categories for every item in the feed.
- """
- item_categories = ("python", "django") # Hard-coded categories.
- # ITEM COPYRIGHT NOTICE (only applicable to Atom feeds) -- One of the
- # following three is optional. The framework looks for them in this
- # order.
- def item_copyright(self, obj):
- """
- Takes an item, as returned by items(), and returns the item's
- copyright notice as a normal Python string.
- """
- def item_copyright(self):
- """
- Returns the copyright notice for every item in the feed.
- """
- item_copyright = 'Copyright (c) 2007, Sally Smith' # Hard-coded copyright notice.
- The low-level framework
- =======================
- Behind the scenes, the high-level RSS framework uses a lower-level framework
- for generating feeds' XML. This framework lives in a single module:
- `django/utils/feedgenerator.py`_.
- You use this framework on your own, for lower-level feed generation. You can
- also create custom feed generator subclasses for use with the ``feed_type``
- ``Feed`` option.
- ``SyndicationFeed`` classes
- ---------------------------
- The :mod:`~django.utils.feedgenerator` module contains a base class:
- .. class:: django.utils.feedgenerator.SyndicationFeed
- and several subclasses:
- .. class:: django.utils.feedgenerator.RssUserland091Feed
- .. class:: django.utils.feedgenerator.Rss201rev2Feed
- .. class:: django.utils.feedgenerator.Atom1Feed
- Each of these three classes knows how to render a certain type of feed as XML.
- They share this interface:
- .. method:: SyndicationFeed.__init__(**kwargs)
- Initialize the feed with the given dictionary of metadata, which applies to
- the entire feed. Required keyword arguments are:
-
- * ``title``
- * ``link``
- * ``description``
-
- There's also a bunch of other optional keywords:
- * ``language``
- * ``author_email``
- * ``author_name``
- * ``author_link``
- * ``subtitle``
- * ``categories``
- * ``feed_url``
- * ``feed_copyright``
- * ``feed_guid``
- * ``ttl``
-
- Any extra keyword arguments you pass to ``__init__`` will be stored in
- ``self.feed`` for use with `custom feed generators`_.
- All parameters should be Unicode objects, except ``categories``, which
- should be a sequence of Unicode objects.
- .. method:: SyndicationFeed.add_item(**kwargs)
- Add an item to the feed with the given parameters.
- Required keyword arguments are:
- * ``title``
- * ``link``
- * ``description``
- Optional keyword arguments are:
- * ``author_email``
- * ``author_name``
- * ``author_link``
- * ``pubdate``
- * ``comments``
- * ``unique_id``
- * ``enclosure``
- * ``categories``
- * ``item_copyright``
- * ``ttl``
- Extra keyword arguments will be stored for `custom feed generators`_.
- All parameters, if given, should be Unicode objects, except:
- * ``pubdate`` should be a `Python datetime object`_.
- * ``enclosure`` should be an instance of ``feedgenerator.Enclosure``.
- * ``categories`` should be a sequence of Unicode objects.
- .. method:: SyndicationFeed.write(outfile, encoding)
- Outputs the feed in the given encoding to outfile, which is a file-like object.
- .. method:: SyndicationFeed.writeString(encoding)
- Returns the feed as a string in the given encoding.
- For example, to create an Atom 1.0 feed and print it to standard output::
- >>> from django.utils import feedgenerator
- >>> f = feedgenerator.Atom1Feed(
- ... title=u"My Weblog",
- ... link=u"http://www.example.com/",
- ... description=u"In which I write about what I ate today.",
- ... language=u"en")
- >>> f.add_item(title=u"Hot dog today",
- ... link=u"http://www.example.com/entries/1/",
- ... description=u"<p>Today I had a Vienna Beef hot dog. It was pink, plump and perfect.</p>")
- >>> print f.writeString('UTF-8')
- <?xml version="1.0" encoding="UTF-8"?>
- <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
- ...
- </feed>
- .. _django/utils/feedgenerator.py: http://code.djangoproject.com/browser/django/trunk/django/utils/feedgenerator.py
- .. _Python datetime object: http://docs.python.org/library/datetime.html#datetime-objects
- Custom feed generators
- ----------------------
- If you need to produce a custom feed format, you've got a couple of options.
-
- If the feed format is totally custom, you'll want to subclass
- ``SyndicationFeed`` and completely replace the ``write()`` and
- ``writeString()`` methods.
- However, if the feed format is a spin-off of RSS or Atom (i.e. GeoRSS_, Apple's
- `iTunes podcast format`_, etc.), you've got a better choice. These types of
- feeds typically add extra elements and/or attributes to the underlying format,
- and there are a set of methods that ``SyndicationFeed`` calls to get these extra
- attributes. Thus, you can subclass the appropriate feed generator class
- (``Atom1Feed`` or ``Rss201rev2Feed``) and extend these callbacks. They are:
-
- .. _georss: http://georss.org/
- .. _itunes podcast format: http://www.apple.com/itunes/store/podcaststechspecs.html
- ``SyndicationFeed.root_attributes(self, )``
- Return a ``dict`` of attributes to add to the root feed element
- (``feed``/``channel``).
-
- ``SyndicationFeed.add_root_elements(self, handler)``
- Callback to add elements inside the root feed element
- (``feed``/``channel``). ``handler`` is an `XMLGenerator`_ from Python's
- built-in SAX library; you'll call methods on it to add to the XML
- document in process.
-
- ``SyndicationFeed.item_attributes(self, item)``
- Return a ``dict`` of attributes to add to each item (``item``/``entry``)
- element. The argument, ``item``, is a dictionary of all the data passed to
- ``SyndicationFeed.add_item()``.
-
- ``SyndicationFeed.add_item_elements(self, handler, item)``
- Callback to add elements to each item (``item``/``entry``) element.
- ``handler`` and ``item`` are as above.
- .. warning::
- If you override any of these methods, be sure to call the superclass methods
- since they add the required elements for each feed format.
- For example, you might start implementing an iTunes RSS feed generator like so::
- class iTunesFeed(Rss201rev2Feed):
- def root_attributes(self):
- attrs = super(iTunesFeed, self).root_attributes()
- attrs['xmlns:itunes'] = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
- return attrs
-
- def add_root_elements(self, handler):
- super(iTunesFeed, self).add_root_elements(handler)
- handler.addQuickElement('itunes:explicit', 'clean')
- Obviously there's a lot more work to be done for a complete custom feed class,
- but the above example should demonstrate the basic idea.
- .. _XMLGenerator: http://docs.python.org/dev/library/xml.sax.utils.html#xml.sax.saxutils.XMLGenerator
|