diff options
author | Nishanth Amuluru | 2011-01-08 11:20:57 +0530 |
---|---|---|
committer | Nishanth Amuluru | 2011-01-08 11:20:57 +0530 |
commit | 65411d01d448ff0cd4abd14eee14cf60b5f8fc20 (patch) | |
tree | b4c404363c4c63a61d6e2f8bd26c5b057c1fb09d /parts/django/docs/ref/contrib/syndication.txt | |
parent | 2e35094d43b4cc6974172e1febf76abb50f086ec (diff) | |
download | pytask-65411d01d448ff0cd4abd14eee14cf60b5f8fc20.tar.gz pytask-65411d01d448ff0cd4abd14eee14cf60b5f8fc20.tar.bz2 pytask-65411d01d448ff0cd4abd14eee14cf60b5f8fc20.zip |
Added buildout stuff and made changes accordingly
--HG--
rename : profile/management/__init__.py => eggs/djangorecipe-0.20-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/djangorecipe-0.20-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/infrae.subversion-1.4.5-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/infrae.subversion-1.4.5-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/mercurial-1.7.3-py2.6-linux-x86_64.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/py-1.4.0-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/py-1.4.0-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/zc.buildout-1.5.2-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/zc.buildout-1.5.2-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => eggs/zc.recipe.egg-1.3.2-py2.6.egg/EGG-INFO/dependency_links.txt
rename : profile/management/__init__.py => eggs/zc.recipe.egg-1.3.2-py2.6.egg/EGG-INFO/not-zip-safe
rename : profile/management/__init__.py => parts/django/Django.egg-info/dependency_links.txt
rename : taskapp/models.py => parts/django/django/conf/app_template/models.py
rename : taskapp/tests.py => parts/django/django/conf/app_template/tests.py
rename : taskapp/views.py => parts/django/django/conf/app_template/views.py
rename : taskapp/views.py => parts/django/django/contrib/gis/tests/geo3d/views.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/delete/__init__.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/files/__init__.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/invalid_models/__init__.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/m2m_signals/__init__.py
rename : profile/management/__init__.py => parts/django/tests/modeltests/model_package/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/management/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/management/commands/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/bash_completion/models.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/delete_regress/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/file_storage/__init__.py
rename : profile/management/__init__.py => parts/django/tests/regressiontests/max_lengths/__init__.py
rename : profile/forms.py => pytask/profile/forms.py
rename : profile/management/__init__.py => pytask/profile/management/__init__.py
rename : profile/management/commands/seed_db.py => pytask/profile/management/commands/seed_db.py
rename : profile/models.py => pytask/profile/models.py
rename : profile/templatetags/user_tags.py => pytask/profile/templatetags/user_tags.py
rename : taskapp/tests.py => pytask/profile/tests.py
rename : profile/urls.py => pytask/profile/urls.py
rename : profile/utils.py => pytask/profile/utils.py
rename : profile/views.py => pytask/profile/views.py
rename : static/css/base.css => pytask/static/css/base.css
rename : taskapp/tests.py => pytask/taskapp/tests.py
rename : taskapp/views.py => pytask/taskapp/views.py
rename : templates/base.html => pytask/templates/base.html
rename : templates/profile/browse_notifications.html => pytask/templates/profile/browse_notifications.html
rename : templates/profile/edit.html => pytask/templates/profile/edit.html
rename : templates/profile/view.html => pytask/templates/profile/view.html
rename : templates/profile/view_notification.html => pytask/templates/profile/view_notification.html
rename : templates/registration/activate.html => pytask/templates/registration/activate.html
rename : templates/registration/activation_email.txt => pytask/templates/registration/activation_email.txt
rename : templates/registration/activation_email_subject.txt => pytask/templates/registration/activation_email_subject.txt
rename : templates/registration/logged_out.html => pytask/templates/registration/logged_out.html
rename : templates/registration/login.html => pytask/templates/registration/login.html
rename : templates/registration/logout.html => pytask/templates/registration/logout.html
rename : templates/registration/password_change_done.html => pytask/templates/registration/password_change_done.html
rename : templates/registration/password_change_form.html => pytask/templates/registration/password_change_form.html
rename : templates/registration/password_reset_complete.html => pytask/templates/registration/password_reset_complete.html
rename : templates/registration/password_reset_confirm.html => pytask/templates/registration/password_reset_confirm.html
rename : templates/registration/password_reset_done.html => pytask/templates/registration/password_reset_done.html
rename : templates/registration/password_reset_email.html => pytask/templates/registration/password_reset_email.html
rename : templates/registration/password_reset_form.html => pytask/templates/registration/password_reset_form.html
rename : templates/registration/registration_complete.html => pytask/templates/registration/registration_complete.html
rename : templates/registration/registration_form.html => pytask/templates/registration/registration_form.html
rename : utils.py => pytask/utils.py
Diffstat (limited to 'parts/django/docs/ref/contrib/syndication.txt')
-rw-r--r-- | parts/django/docs/ref/contrib/syndication.txt | 949 |
1 files changed, 949 insertions, 0 deletions
diff --git a/parts/django/docs/ref/contrib/syndication.txt b/parts/django/docs/ref/contrib/syndication.txt new file mode 100644 index 0000000..04f14b5 --- /dev/null +++ b/parts/django/docs/ref/contrib/syndication.txt @@ -0,0 +1,949 @@ +============================== +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 +======================== + +.. versionchanged:: 1.2 + The high-level feeds framework was refactored in Django 1.2. The + pre-1.2 interface still exists, but it has been deprecated, and + will be removed in Django 1.4. If you need to maintain an old-style + Django feed, please consult the Django 1.1 documentation. For + details on updating to use the new high-level feed framework, see + the :ref:`Django 1.2 release notes <1.2-updating-feeds>`. + +Overview +-------- + +The high-level feed-generating framework is supplied by the +:class:`~django.contrib.syndication.views.Feed` class. To create a +feed, write a :class:`~django.contrib.syndication.views.Feed` class +and point to an instance of it in your :doc:`URLconf +</topics/http/urls>`. + +Feed classes +------------ + +A :class:`~django.contrib.syndication.views.Feed` class is a 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). + +Feed classes subclass :class:`django.contrib.syndication.views.Feed`. +They can live anywhere in your codebase. + +Instances of :class:`~django.contrib.syndication.views.Feed` classes +are views which can be used in your :doc:`URLconf </topics/http/urls>`. + +A simple example +---------------- + +This simple example, taken from `chicagocrime.org`_, describes a feed of the +latest five news items:: + + from django.contrib.syndication.views import Feed + from chicagocrime.models import NewsItem + + class LatestEntriesFeed(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] + + def item_title(self, item): + return item.title + + def item_description(self, item): + return item.description + +To connect a URL to this feed, put an instance of the Feed object in +your :doc:`URLconf </topics/http/urls>`. For example:: + + from django.conf.urls.defaults import * + from myproject.feeds import LatestEntriesFeed + + urlpatterns = patterns('', + # ... + (r'^latest/feed/$', LatestEntriesFeed()), + # ... + ) + +Note: + +* The Feed class subclasses :class:`django.contrib.syndication.views.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 + :doc:`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 is 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. + + * For the contents of ``<title>`` and ``<description>``, Django tries + calling the methods :meth:`item_title()` and :meth:`item_description()` on + the :class:`~django.contrib.syndication.views.Feed` class. They are passed + a single parameter, :attr:`item`, which is the object itself. These are + optional; by default, the unicode representation of the object is used for + both. + + If you want to do any special formatting for either the title or + description, :doc:`Django templates </topics/templates>` can be used + instead. Their paths can be specified with the ``title_template`` and + ``description_template`` attributes on the + :class:`~django.contrib.syndication.views.Feed` class. The templates are + rendered for each item and are passed 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. + + See `a complex example`_ below that uses a description template. + + * To specify the contents of ``<link>``, you have two options. For each item + in :meth:`items()`, Django first tries calling the + :meth:`item_link()` method on the + :class:`~django.contrib.syndication.views.Feed` class. In a similar way to + the title and description, it is passed it a single parameter, + :attr:`item`. If that method doesn't exist, Django tries executing a + ``get_absolute_url()`` method on that object. Both + :meth:`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. + +.. _chicagocrime.org: http://www.chicagocrime.org/ + +A complex example +----------------- + +The framework also supports more complex feeds, via arguments. + +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.views.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 access the +arguments passed from your :doc:`URLconf </topics/http/urls>` so feeds can output +items based on information in the feed's URL. + +On chicagocrime.org, the police-beat feeds are accessible via URLs like this: + + * :file:`/beats/613/rss/` -- Returns recent crimes for beat 613. + * :file:`/beats/1424/rss/` -- Returns recent crimes for beat 1424. + +These can be matched with a :doc:`URLconf </topics/http/urls>` line such as:: + + (r'^beats/(?P<beat_id>\d+)/rss/$', BeatFeed()), + +Like a view, the arguments in the URL are passed to the :meth:`get_object()` +method along with the request object. + +.. versionchanged:: 1.2 + Prior to version 1.2, ``get_object()`` only accepted a ``bits`` argument. + +Here's the code for these beat-specific feeds:: + + from django.contrib.syndication.views import FeedDoesNotExist + from django.shortcuts import get_object_or_404 + + class BeatFeed(Feed): + description_template = 'feeds/beat_description.html' + + def get_object(self, request, beat_id): + return get_object_or_404(Beat, pk=beat_id) + + def title(self, obj): + return "Chicagocrime.org: Crimes for beat %s" % obj.beat + + def link(self, obj): + 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=obj).order_by('-crime_date')[:30] + +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. + +Also note that :meth:`items()` also follows the same algorithm -- first, it +tries :meth:`items(obj)`, then :meth:`items()`, then finally an :attr:`items` +class attribute (which should be a list). + +We are using a template for the item descriptions. It can be very simple: + +.. code-block:: html+django + + {{ obj.description }} + +However, you are free to add formatting as desired. + +The ``ExampleFeed`` class below gives full documentation on methods and +attributes of :class:`~django.contrib.syndication.views.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.views.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 path (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.views.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.views 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.views.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 + + urlpatterns = patterns('', + # ... + (r'^sitenews/rss/$', RssSiteNewsFeed()), + (r'^sitenews/atom/$', AtomSiteNewsFeed()), + # ... + ) + +Feed class reference +-------------------- + +.. class:: django.contrib.syndication.views.Feed + +This example illustrates all possible attributes and methods for a +:class:`~django.contrib.syndication.views.Feed` class:: + + from django.contrib.syndication.views 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 a template is not specified, the + # item_title() or item_description() methods are used instead. + + 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 feed_copyright(self, obj): + """ + Takes the object returned by get_object() and returns the feed's + copyright notice as a normal Python string. + """ + + def feed_copyright(self): + """ + Returns the feed's copyright notice as a normal Python string. + """ + + feed_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, request, *args, **kwargs): + """ + Takes the current request and the arguments from the URL, and + returns an object represented by this feed. Raises + django.core.exceptions.ObjectDoesNotExist on error. + """ + + # ITEM TITLE AND DESCRIPTION -- If title_template or + # description_template are not defined, these are used instead. Both are + # optional, by default they will use the unicode representation of the + # item. + + def item_title(self, item): + """ + Takes an item, as returned by items(), and returns the item's + title as a normal Python string. + """ + + def item_title(self): + """ + Returns the title for every item in the feed. + """ + + item_title = 'Breaking News: Nothing Happening' # Hard-coded title. + + def item_description(self, item): + """ + Takes an item, as returned by items(), and returns the item's + description as a normal Python string. + """ + + def item_description(self): + """ + Returns the description for every item in the feed. + """ + + item_description = 'A description of the item.' # Hard-coded description. + + # 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. 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 + >>> from datetime import datetime + >>> 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", + ... author_name=u"Myself", + ... feed_url=u"http://example.com/atom.xml") + >>> f.add_item(title=u"Hot dog today", + ... link=u"http://www.example.com/entries/1/", + ... pubdate=datetime.now(), + ... 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/podcasts/specs.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 |