Permalink
Browse files

Completely refactored legacy RSS framework to the new django.contrib.…

…syndication package. Also added Atom support, changed the way feeds are registered and added documentation for the whole lot. This is backwards-incompatible, but the RSS framework had not yet been documented, so this should only affect tinkerers and WorldOnline. Fixes #329, #498, #502 and #554. Thanks for various patches/ideas to alastair, ismael, hugo, eric moritz and garthk

git-svn-id: http://code.djangoproject.com/svn/django/trunk@1194 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent e8ae356 commit 944de9e9e638bc239b03f67f459ad4abe4673e48 @adrianholovaty adrianholovaty committed Nov 12, 2005
@@ -1,6 +0,0 @@
-from django.conf.urls.defaults import *
-
-urlpatterns = patterns('django.views',
- (r'^(?P<slug>[^/]+)/$', 'rss.rss.feed'),
- (r'^(?P<slug>[^/]+)/(?P<param>.+)/$', 'rss.rss.feed'),
-)
@@ -0,0 +1,89 @@
+from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
+from django.core.template import Context, loader, Template, TemplateDoesNotExist
+from django.models.core import sites
+from django.utils import feedgenerator
+from django.conf.settings import LANGUAGE_CODE, SETTINGS_MODULE
+
+def add_domain(domain, url):
+ if not url.startswith('http://'):
+ url = u'http://%s%s' % (domain, url)
+ return url
+
+class FeedDoesNotExist(ObjectDoesNotExist):
+ pass
+
+class Feed:
+ item_pubdate = None
+ item_enclosure_url = None
+ feed_type = feedgenerator.DefaultFeed
+
+ def __init__(self, slug):
+ self.slug = slug
+
+ def item_link(self, item):
+ try:
+ return item.get_absolute_url()
+ except AttributeError:
+ raise ImproperlyConfigured, "Give your %s class a get_absolute_url() method, or define an item_link() method in your Feed class." % item.__class__.__name__
+
+ def __get_dynamic_attr(self, attname, obj):
+ attr = getattr(self, attname)
+ if callable(attr):
+ try:
+ return attr(obj)
+ except TypeError:
+ return attr()
+ return attr
+
+ def get_feed(self, url=None):
+ """
+ Returns a feedgenerator.DefaultFeed object, fully populated, for
+ this feed. Raises FeedDoesNotExist for invalid parameters.
+ """
+ if url:
+ try:
+ obj = self.get_object(url.split('/'))
+ except (AttributeError, ObjectDoesNotExist):
+ raise FeedDoesNotExist
+ else:
+ obj = None
+
+ current_site = sites.get_current()
+ link = self.__get_dynamic_attr('link', obj)
+ link = add_domain(current_site.domain, link)
+
+ feed = self.feed_type(
+ title = self.__get_dynamic_attr('title', obj),
+ link = link,
+ description = self.__get_dynamic_attr('description', obj),
+ language = LANGUAGE_CODE.decode()
+ )
+
+ try:
+ title_template = loader.get_template('feeds/%s_title' % self.slug)
+ except TemplateDoesNotExist:
+ title_template = Template('{{ obj }}')
+ try:
+ description_template = loader.get_template('feeds/%s_description' % self.slug)
+ except TemplateDoesNotExist:
+ description_template = Template('{{ obj }}')
+
+ for item in self.__get_dynamic_attr('items', obj):
+ link = add_domain(current_site.domain, self.__get_dynamic_attr('item_link', item))
+ enc = None
+ enc_url = self.__get_dynamic_attr('item_enclosure_url', item)
+ if enc_url:
+ enc = feedgenerator.Enclosure(
+ url = enc_url.decode('utf-8'),
+ length = str(self.__get_dynamic_attr('item_enclosure_length', item)).decode('utf-8'),
+ mime_type = self.__get_dynamic_attr('item_enclosure_mime_type', item).decode('utf-8'),
+ )
+ feed.add_item(
+ title = title_template.render(Context({'obj': item, 'site': current_site})).decode('utf-8'),
+ link = link,
+ description = description_template.render(Context({'obj': item, 'site': current_site})).decode('utf-8'),
+ unique_id = link,
+ enclosure = enc,
+ pubdate = self.__get_dynamic_attr('item_pubdate', item),
+ )
+ return feed
@@ -0,0 +1,26 @@
+from django.contrib.syndication import feeds
+from django.core.exceptions import Http404
+from django.utils.httpwrappers import HttpResponse
+
+def feed(request, url, feed_dict=None):
+ if not feed_dict:
+ raise Http404, "No feeds are registered."
+
+ try:
+ slug, param = url.split('/', 1)
+ except ValueError:
+ slug, param = url, ''
+
+ try:
+ f = feed_dict[slug]
+ except KeyError:
+ raise Http404, "Slug %r isn't registered." % slug
+
+ try:
+ feedgen = f(slug).get_feed(param)
+ except feeds.FeedDoesNotExist:
+ raise Http404, "Invalid feed parameters. Slug %r is valid, but other parameters, or lack thereof, are not." % slug
+
+ response = HttpResponse(mimetype='application/xml')
+ feedgen.write(response, 'utf-8')
+ return response
View
@@ -1,223 +0,0 @@
-from django.core.exceptions import ImproperlyConfigured, ObjectDoesNotExist
-from django.core.template import Context, loader, Template, TemplateDoesNotExist
-from django.models.core import sites
-from django.utils import feedgenerator
-from django.conf.settings import LANGUAGE_CODE, SETTINGS_MODULE
-
-def add_domain(domain, url):
- if not url.startswith('http://'):
- url = u'http://%s%s' % (domain, url)
- return url
-
-class FeedDoesNotExist(ObjectDoesNotExist):
- pass
-
-class Feed:
- item_pubdate = None
- item_enclosure_url = None
-
- def item_link(self, item):
- try:
- return item.get_absolute_url()
- except AttributeError:
- raise ImproperlyConfigured, "Give your %s class a get_absolute_url() method, or define an item_link() method in your RSS class." % item.__class__.__name__
-
- def __get_dynamic_attr(self, attname, obj):
- attr = getattr(self, attname)
- if callable(attr):
- try:
- return attr(obj)
- except TypeError:
- return attr()
- return attr
-
- def get_feed(self, url=None):
- """
- Returns a feedgenerator.DefaultRssFeed object, fully populated, for
- this feed. Raises FeedDoesNotExist for invalid parameters.
- """
- if url:
- try:
- obj = self.get_object(url.split('/'))
- except (AttributeError, ObjectDoesNotExist):
- raise FeedDoesNotExist
- else:
- obj = None
-
- current_site = sites.get_current()
- link = self.__get_dynamic_attr('link', obj)
- link = add_domain(current_site.domain, link)
-
- feed = feedgenerator.DefaultRssFeed(
- title = self.__get_dynamic_attr('title', obj),
- link = link,
- description = self.__get_dynamic_attr('description', obj),
- language = LANGUAGE_CODE.decode()
- )
-
- try:
- title_template = loader.get_template('rss/%s_title' % self.slug)
- except TemplateDoesNotExist:
- title_template = Template('{{ obj }}')
- try:
- description_template = loader.get_template('rss/%s_description' % self.slug)
- except TemplateDoesNotExist:
- description_template = Template('{{ obj }}')
-
- for item in self.__get_dynamic_attr('items', obj):
- link = add_domain(current_site.domain, self.__get_dynamic_attr('item_link', item))
- enc = None
- enc_url = self.__get_dynamic_attr('item_enclosure_url', item)
- if enc_url:
- enc = feedgenerator.Enclosure(
- url = enc_url.decode('utf-8'),
- length = str(self.__get_dynamic_attr('item_enclosure_length', item)).decode('utf-8'),
- mime_type = self.__get_dynamic_attr('item_enclosure_mime_type', item).decode('utf-8'),
- )
- feed.add_item(
- title = title_template.render(Context({'obj': item, 'site': current_site})).decode('utf-8'),
- link = link,
- description = description_template.render(Context({'obj': item, 'site': current_site})).decode('utf-8'),
- unique_id = link,
- enclosure = enc,
- pubdate = self.__get_dynamic_attr('item_pubdate', item),
- )
- return feed
-
-# DEPRECATED
-class FeedConfiguration:
- def __init__(self, slug, title_cb, link_cb, description_cb, get_list_func_cb, get_list_kwargs,
- param_func=None, param_kwargs_cb=None, get_list_kwargs_cb=None, get_pubdate_cb=None,
- enc_url=None, enc_length=None, enc_mime_type=None):
- """
- slug -- Normal Python string. Used to register the feed.
-
- title_cb, link_cb, description_cb -- Functions that take the param
- (if applicable) and return a normal Python string.
-
- get_list_func_cb -- Function that takes the param and returns a
- function to use in retrieving items.
-
- get_list_kwargs -- Dictionary of kwargs to pass to the function
- returned by get_list_func_cb.
-
- param_func -- Function to use in retrieving the param (if applicable).
-
- param_kwargs_cb -- Function that takes the slug and returns a
- dictionary of kwargs to use in param_func.
-
- get_list_kwargs_cb -- Function that takes the param and returns a
- dictionary to use in addition to get_list_kwargs (if applicable).
-
- get_pubdate_cb -- Function that takes the object and returns a datetime
- to use as the publication date in the feed.
-
- The three enc_* parameters are strings representing methods or
- attributes to call on a particular item to get its enclosure
- information. Each of those methods/attributes should return a normal
- Python string.
- """
- self.slug = slug
- self.title_cb, self.link_cb = title_cb, link_cb
- self.description_cb = description_cb
- self.get_list_func_cb = get_list_func_cb
- self.get_list_kwargs = get_list_kwargs
- self.param_func, self.param_kwargs_cb = param_func, param_kwargs_cb
- self.get_list_kwargs_cb = get_list_kwargs_cb
- self.get_pubdate_cb = get_pubdate_cb
- assert (None == enc_url == enc_length == enc_mime_type) or (enc_url is not None and enc_length is not None and enc_mime_type is not None)
- self.enc_url = enc_url
- self.enc_length = enc_length
- self.enc_mime_type = enc_mime_type
-
- def get_feed(self, param_slug=None):
- """
- Returns a utils.feedgenerator.DefaultRssFeed object, fully populated,
- representing this FeedConfiguration.
- """
- if param_slug:
- try:
- param = self.param_func(**self.param_kwargs_cb(param_slug))
- except ObjectDoesNotExist:
- raise FeedIsNotRegistered
- else:
- param = None
- current_site = sites.get_current()
- f = self._get_feed_generator_object(param)
- title_template = loader.get_template('rss/%s_title' % self.slug)
- description_template = loader.get_template('rss/%s_description' % self.slug)
- kwargs = self.get_list_kwargs.copy()
- if param and self.get_list_kwargs_cb:
- kwargs.update(self.get_list_kwargs_cb(param))
- get_list_func = self.get_list_func_cb(param)
- for obj in get_list_func(**kwargs):
- link = obj.get_absolute_url()
- if not link.startswith('http://'):
- link = u'http://%s%s' % (current_site.domain, link)
- enc = None
- if self.enc_url:
- enc_url = getattr(obj, self.enc_url)
- enc_length = getattr(obj, self.enc_length)
- enc_mime_type = getattr(obj, self.enc_mime_type)
- try:
- enc_url = enc_url()
- except TypeError:
- pass
- try:
- enc_length = enc_length()
- except TypeError:
- pass
- try:
- enc_mime_type = enc_mime_type()
- except TypeError:
- pass
- enc = feedgenerator.Enclosure(enc_url.decode('utf-8'),
- (enc_length and str(enc_length).decode('utf-8') or ''), enc_mime_type.decode('utf-8'))
- f.add_item(
- title = title_template.render(Context({'obj': obj, 'site': current_site})).decode('utf-8'),
- link = link,
- description = description_template.render(Context({'obj': obj, 'site': current_site})).decode('utf-8'),
- unique_id=link,
- enclosure=enc,
- pubdate = self.get_pubdate_cb and self.get_pubdate_cb(obj) or None,
- )
- return f
-
- def _get_feed_generator_object(self, param):
- current_site = sites.get_current()
- link = self.link_cb(param).decode()
- if not link.startswith('http://'):
- link = u'http://%s%s' % (current_site.domain, link)
- return feedgenerator.DefaultRssFeed(
- title = self.title_cb(param).decode(),
- link = link,
- description = self.description_cb(param).decode(),
- language = LANGUAGE_CODE.decode(),
- )
-
-
-# global dict used by register_feed and get_registered_feed
-_registered_feeds = {}
-
-# DEPRECATED
-class FeedIsNotRegistered(Exception):
- pass
-
-# DEPRECATED
-def register_feed(feed):
- _registered_feeds[feed.slug] = feed
-
-def register_feeds(*feeds):
- for f in feeds:
- _registered_feeds[f.slug] = f
-
-def get_registered_feed(slug):
- # try to load a RSS settings module so that feeds can be registered
- try:
- __import__(SETTINGS_MODULE + '_rss', '', '', [''])
- except (KeyError, ImportError, ValueError):
- pass
- try:
- return _registered_feeds[slug]
- except KeyError:
- raise FeedIsNotRegistered
Oops, something went wrong.

0 comments on commit 944de9e

Please sign in to comment.