diff options
| author | Russell Keith-Magee <russell@keith-magee.com> | 2010-01-28 13:46:18 +0000 |
|---|---|---|
| committer | Russell Keith-Magee <russell@keith-magee.com> | 2010-01-28 13:46:18 +0000 |
| commit | c4c27d8a04c9125cfbc5c3611557d8e5d3845b0d (patch) | |
| tree | 8aa6ee0d5b19ff096dc597e884dfa402d6ac8829 /docs | |
| parent | 3f68d255e24b5696537572ff351a8ad9f91d1b9d (diff) | |
Fixed #6188, #6304, #6618, #6969, #8758, #8989, #10334, #11069, #11973 and #12403 -- Modified the syndication framework to use class-based views. Thanks to Ben Firshman for his work on this patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@12338 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/internals/deprecation.txt | 4 | ||||
| -rw-r--r-- | docs/ref/contrib/syndication.txt | 403 | ||||
| -rw-r--r-- | docs/releases/1.2.txt | 92 |
3 files changed, 278 insertions, 221 deletions
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt index c3aa55e9d8..f2ae31d4be 100644 --- a/docs/internals/deprecation.txt +++ b/docs/internals/deprecation.txt @@ -82,6 +82,10 @@ their deprecation, as per the :ref:`Django deprecation policy * The ability to use a function-based test runners will be removed, along with the ``django.test.simple.run_tests()`` test runner. + * The ``views.feed()`` view and ``feeds.Feed`` class in + ``django.contrib.syndication`` have been deprecated since the 1.2 + release. The class-based view ``views.Feed`` should be used instead. + * 2.0 * ``django.views.defaults.shortcut()``. This function has been moved to ``django.contrib.contenttypes.views.shortcut()`` as part of the diff --git a/docs/ref/contrib/syndication.txt b/docs/ref/contrib/syndication.txt index c27666303c..5c670c7834 100644 --- a/docs/ref/contrib/syndication.txt +++ b/docs/ref/contrib/syndication.txt @@ -8,14 +8,15 @@ The syndication feed framework :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. +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. +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. +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/ @@ -23,74 +24,37 @@ to generate feeds outside of a Web context, or in some other lower-level way. 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 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. +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 :ref:`URLconf +<topics-http-urls>`. 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). +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. -:class:`~django.contrib.syndication.feeds.Feed` classes must subclass -``django.contrib.syndication.feeds.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 :ref:`URLconf <topics-http-urls>`. A simple example ---------------- @@ -98,10 +62,10 @@ 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 django.contrib.syndication.views import Feed from chicagocrime.models import NewsItem - class LatestEntries(Feed): + class LatestEntriesFeed(Feed): title = "Chicagocrime.org site news" link = "/sitenews/" description = "Updates on changes and additions to chicagocrime.org." @@ -109,9 +73,27 @@ latest five news items:: 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 :ref:`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 class subclasses ``django.contrib.syndication.feeds.Feed``. +* 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, @@ -129,17 +111,23 @@ Note: :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>``, +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. - * 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: + * 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, :ref:`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()`). @@ -152,152 +140,102 @@ into those elements. :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. + 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 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. If that method doesn't exist, Django tries executing a - ``get_absolute_url()`` method on that object. . 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 }} + 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 parameters. +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.feeds.Feed` class for each police beat; that +: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 make generic -feeds that output items based on information in the feed's URL. +programming logic. Instead, the syndication framework lets you access the +arguments passed from your :ref:`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:`/rss/beats/0613/` -- Returns recent crimes for beat 0613. - * :file:`/rss/beats/1424/` -- Returns recent crimes for beat 1424. + * :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 :ref:`URLconf <topics-http-urls>` line such as:: + + (r'^beats/(?P<beat_id>\d+)/rss/$', BeatFeed()), -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. +Like a view, the arguments in the URL are passed to the :meth:`get_object()` +method along with the request object. -An example makes this clear. Here's the code for these beat-specific feeds:: +.. versionchanged:: 1.2 + Prior to version 1.2, ``get_object()`` only accepted a ``bits`` argument. - from django.contrib.syndication.feeds import FeedDoesNotExist - from django.core.exceptions import ObjectDoesNotExist +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): - 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]) + 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): - 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']``. + return Crime.objects.filter(beat=obj).order_by('-crime_date')[:30] - * :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. +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: - .. versionadded:: 1.0 - :meth:`get_object()` can handle the :file:`/rss/beats/` url. + * First, it tries to call a method, passing the ``obj`` argument, where + ``obj`` is the object returned by :meth:`get_object()`. - 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. + * Failing that, it tries to call a method with no arguments. - * 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: + * Failing that, it uses the class attribute. - * First, it tries to call a method, passing the ``obj`` argument, where - ``obj`` is the object returned by :meth:`get_object()`. +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). - * Failing that, it tries to call a method with no arguments. +We are using a template for the item descriptions. It can be very simple: - * Failing that, it uses the class attribute. +.. code-block:: html+django - 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.) + {{ obj.description }} - * 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). +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.feeds.Feed` classes. +attributes of :class:`~django.contrib.syndication.views.Feed` classes. Specifying the type of feed --------------------------- @@ -305,7 +243,7 @@ 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:: +:class:`~django.contrib.syndication.views.Feed` class, like so:: from django.utils.feedgenerator import Atom1Feed @@ -353,13 +291,13 @@ 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:`~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.feeds import Feed + from django.contrib.syndication.views import Feed from chicagocrime.models import NewsItem from django.utils.feedgenerator import Atom1Feed @@ -381,7 +319,7 @@ Here's a full example:: 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* + :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. @@ -394,56 +332,50 @@ 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}), + (r'^sitenews/rss/$', RssSiteNewsFeed()), + (r'^sitenews/atom/$', AtomSiteNewsFeed()), # ... ) Feed class reference -------------------- -.. class:: django.contrib.syndication.feeds.Feed +.. class:: django.contrib.syndication.views.Feed This example illustrates all possible attributes and methods for a -:class:`~django.contrib.syndication.feeds.Feed` class:: +:class:`~django.contrib.syndication.views.Feed` class:: - from django.contrib.syndication.feeds import Feed + 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. + # 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. + # 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. + # 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. + Takes the object returned by get_object() and returns the + feed's title as a normal Python string. """ def title(self): @@ -453,13 +385,13 @@ This example illustrates all possible attributes and methods for a title = 'foo' # Hard-coded title. - # LINK -- One of the following three is required. The framework looks - # for them in this order. + # 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. + # Takes the object returned by get_object() and returns the feed's + # link as a normal Python string. """ def link(self): @@ -572,18 +504,18 @@ This example illustrates all possible attributes and methods for a # COPYRIGHT NOTICE -- One of the following three is optional. The # framework looks for them in this order. - def copyright(self, obj): + 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 copyright(self): + def feed_copyright(self): """ Returns the feed's copyright notice as a normal Python string. """ - copyright = 'Copyright (c) 2007, Sally Smith' # Hard-coded copyright notice. + 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. @@ -620,13 +552,44 @@ This example illustrates all possible attributes and methods for a # 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): + def get_object(self, request, *args, **kwargs): """ - Takes a list of strings gleaned from the URL and returns an object - represented by this feed. Raises + 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. @@ -686,7 +649,7 @@ This example illustrates all possible attributes and methods for a item_author_email = 'test@example.com' # Hard-coded author e-mail. - # ITEM AUTHOR LINK --One of the following three is optional. The + # 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. # diff --git a/docs/releases/1.2.txt b/docs/releases/1.2.txt index a7660ae922..f4826787c2 100644 --- a/docs/releases/1.2.txt +++ b/docs/releases/1.2.txt @@ -386,6 +386,87 @@ approach. Old style function-based test runners will still work, but should be updated to use the new :ref:`class-based runners <topics-testing-test_runner>`. +.. _1.2-updating-feeds: + +``Feed`` in ``django.contrib.syndication.feeds`` +------------------------------------------------ + +The :class:`django.contrib.syndication.feeds.Feed` class has been +replaced by the :class:`django.contrib.syndication.views.Feed` class. +The old ``feeds.Feed`` class is deprecated, and will be removed in +Django 1.4. + +The new class has an almost identical API, but allows instances to be +used as views. For example, consider the use of the old framework in +the following :ref:`URLconf <topics-http-urls>`:: + + 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}), + # ... + ) + +Using the new Feed class, these feeds can be deployed directly as views:: + + from django.conf.urls.defaults import * + from myproject.feeds import LatestEntries, LatestEntriesByCategory + + urlpatterns = patterns('', + # ... + (r'^feeds/latest/$', LatestEntries()), + (r'^feeds/categories/(?P<category_id>\d+)/$', LatestEntriesByCategory()), + # ... + ) + +If you currently use the ``feed()`` view, the ``LatestEntries`` class +would not need to be modified apart from subclassing the new +:class:`~django.contrib.syndication.views.Feed` class. + +However, ``LatestEntriesByCategory`` uses the ``get_object()`` method +with the ``bits`` argument to specify a specific category to show. In +the new :class:`~django.contrib.syndication.views.Feed` class, +``get_object()`` method takes a ``request`` and arguments from the +URL, so it would look like this:: + + from django.contrib.syndication.views import Feed + from django.shortcuts import get_object_or_404 + from myproject.models import Category + + class LatestEntriesByCategory(Feed): + def get_object(self, request, category_id): + return get_object_or_404(Category, id=category_id) + + # ... + +Additionally, the ``get_feed()`` method on ``Feed`` classes now take +different arguments, which may impact you if you use the ``Feed`` +classes directly. Instead of just taking an optional ``url`` argument, +it now takes two arguments: the object returned by its own +``get_object()`` method, and the current ``request`` object. + +To take into account ``Feed`` classes not being initialized for each +request, the ``__init__()`` method now takes no arguments by default. +Previously it would have taken the ``slug`` from the URL and the +``request`` object. + +In accordance with `RSS best practices`_, RSS feeds will now include +an ``atom:link`` element. You may need to update your tests to take +this into account. + +For more information, see the full :ref:`syndication framework +documentation <ref-contrib-syndication>`. + +.. _RSS best practices: http://www.rssboard.org/rss-profile + What's new in Django 1.2 ======================== @@ -556,7 +637,7 @@ Object-level permissions A foundation for specifying permissions at the per-object level has been added. Although there is no implementation of this in core, a custom authentication backend can provide this implementation and it will be used by -:class:`django.contrib.auth.models.User`. See the :ref:`authentication docs +:class:`django.contrib.auth.models.User`. See the :ref:`authentication docs <topics-auth>` for more information. Permissions for anonymous users @@ -568,3 +649,12 @@ User already did. This is useful for centralizing permission handling - apps can always delegate the question of whether something is allowed or not to the authorization/authentication backend. See the :ref:`authentication docs <topics-auth>` for more details. + +Syndication feeds as views +-------------------------- + +:ref:`Syndication feeds <ref-contrib-syndication>` can now be used directly as +views in your :ref:`URLconf <topics-http-urls>`. This means that you can +maintain complete control over the URL structure of your feeds. Like any other view, feeds views are passed a ``request`` object, so you can +do anything you would normally do with a view, like user based access control, +or making a feed a named URL. |
