Ticket #6304: single_feed.diff

File single_feed.diff, 7.0 KB (added by Adrian Holovaty, 16 years ago)

Implementation of single_feed()

  • django/contrib/syndication/views.py

     
    11from django.contrib.syndication import feeds
    22from django.http import HttpResponse, Http404
    33
    4 def feed(request, url, feed_dict=None):
     4def multiple_feeds(request, url, feed_dict=None):
    55    if not feed_dict:
    6         raise Http404, "No feeds are registered."
     6        raise Http404("No feeds are registered.")
    77
     8    url_params = url.split('/')
    89    try:
    9         slug, param = url.split('/', 1)
    10     except ValueError:
    11         slug, param = url, ''
     10        slug, rest = url_params[0], url_params[1:]
     11    except IndexError:
     12        raise Http404("Slug not provided.")
    1213
    1314    try:
    14         f = feed_dict[slug]
     15        feed_class = feed_dict[slug]
    1516    except KeyError:
    16         raise Http404, "Slug %r isn't registered." % slug
     17        raise Http404("Slug %r isn't registered." % slug)
    1718
     19    return single_feed(request, slug, *rest, **{'feed_class': feed_class})
     20
     21# This function used to be called feed(). Keep this alias for backwards
     22# compatibility.
     23feed = multiple_feeds
     24
     25def single_feed(request, slug, *url_args, **url_kwargs):
    1826    try:
    19         feedgen = f(slug, request).get_feed(param)
     27        feed_class = url_kwargs.pop('feed_class')
     28    except KeyError:
     29        raise ValueError('single_feed() requires a `feed_class` keyword argument')
     30    if url_kwargs:
     31        raise ValueError('single_feed() got unknown keyword argument(s): %s' % ', '.join(url_kwargs.keys()))
     32    try:
     33        feedgen = feed_class(slug, request).get_feed(url_args)
    2034    except feeds.FeedDoesNotExist:
    21         raise Http404, "Invalid feed parameters. Slug %r is valid, but other parameters, or lack thereof, are not." % slug
    22 
     35        raise Http404("Invalid feed parameters: %r" % (url_args,))
    2336    response = HttpResponse(mimetype=feedgen.mime_type)
    2437    feedgen.write(response, 'utf-8')
    2538    return response
  • django/contrib/syndication/feeds.py

     
    5555                return attr()
    5656        return attr
    5757
    58     def get_feed(self, url=None):
     58    def get_feed(self, url_params):
    5959        """
    6060        Returns a feedgenerator.DefaultFeed object, fully populated, for
    6161        this feed. Raises FeedDoesNotExist for invalid parameters.
    6262        """
    63         if url:
     63        # url_params is a list of captured parameters (as strings) from the
     64        # URLconf. It can be empty.
     65        if url_params:
    6466            try:
    65                 obj = self.get_object(url.split('/'))
     67                obj = self.get_object(url_params)
    6668            except (AttributeError, ObjectDoesNotExist):
    6769                raise FeedDoesNotExist
    6870        else:
  • docs/syndication_feeds.txt

     
    4040To activate syndication feeds on your Django site, add this line to your
    4141URLconf_::
    4242
    43     (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}),
     43    (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.multiple_feeds', {'feed_dict': feeds}),
    4444
    4545This tells Django to use the RSS framework to handle all URLs starting with
    4646``"feeds/"``. (You can change that ``"feeds/"`` prefix to fit your own needs.)
    4747
     48(Note that this ``multiple_feeds`` view used to be called ``feed``, but it's
     49been renamed in the Django development version to be clearer, and to allow for
     50other feed views, such as ``single_feed()``, which is explained below. However,
     51if your code refers to the ``feed`` view, it will still work.)
     52
    4853This URLconf line has an extra argument: ``{'feed_dict': feeds}``. Use this
    4954extra argument to pass the syndication framework the feeds that should be
    5055published under that URL.
     
    6570
    6671    urlpatterns = patterns('',
    6772        # ...
    68         (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
     73        (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.multiple_feeds',
    6974            {'feed_dict': feeds}),
    7075        # ...
    7176    )
     
    377382
    378383    urlpatterns = patterns('',
    379384        # ...
    380         (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
     385        (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.multiple_feeds',
    381386            {'feed_dict': feeds}),
    382387        # ...
    383388    )
     
    786791
    787792        item_copyright = 'Copyright (c) 2007, Sally Smith' # Hard-coded copyright notice.
    788793
     794The ``single_feed()`` view
     795--------------------------
    789796
     797**New in Django development version**
     798
     799Above, we explained that your URLconf should point at the ``multiple_feeds()``
     800view, like so::
     801
     802    (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.multiple_feeds', {'feed_dict': feeds}),
     803
     804However, as explained above, the ``multiple_feeds()`` view makes a few
     805assumptions that may not be appropriate for your particular setup. Specifically:
     806
     807    * It assumes you have multiple feeds. It's overkill to have to define a
     808      ``feed_dict`` if you only have a single feed.
     809
     810    * It uses very simple URL parsing -- the captured value of ``url`` is
     811      simply split by the slash character (``'/'``) and passed to
     812      ``Feed.get_object()``. This is slightly inconvenient in that it requires
     813      your ``Feed`` class to handle URL parsing.
     814
     815As an alternative to the ``multiple_feeds()`` view, Django provides a
     816``single_feed()`` view. The difference here is that ``single_feed()`` only
     817applies to a single ``Feed`` class (as opposed to a ``feed_dict``), and it
     818accepts captured URL arguments, which means you can keep your URL-parsing
     819logic in your URLconf.
     820
     821For example, consider the chicagocrime.org "per-beat" feed explained above.
     822Recall the per-beat feeds, with URLs like this:
     823
     824    * ``/rss/beats/0613/`` -- Returns recent crimes for beat 0613.
     825    * ``/rss/beats/1424/`` -- Returns recent crimes for beat 1424.
     826
     827In the implementation above, the URL parsing was handled in
     828``BeatFeed.get_object()``. But using ``single_feed()``, we can implement the
     829URL parsing in the URLconf, like this::
     830
     831    (r'^feeds/(beats)/(\d\d\d\d)/$', 'django.contrib.syndication.views.multiple_feeds',
     832        {'feed_class': feeds.BlockFeed}),
     833
     834Then, with the URL parsing taken care of by the URLconf,
     835``BeatFeed.get_object()`` no longer has to parse a string. Instead, it's passed
     836a list of parameters captured from the URL::
     837
     838    class BeatFeed(Feed):
     839        def get_object(self, bits):
     840            return Beat.objects.get(beat__exact=bits[0])
     841
     842Note that, unlike the ``single_feed()`` implementation of
     843``BeatFeed.get_object()``, here we don't have to worry about checking for a
     844wacky URL such as ``"/rss/beats/0613/foo/bar/baz/"``, because that will have
     845been caught by the URLconf.
     846
    790847The low-level framework
    791848=======================
    792849
Back to Top