Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Test case and docs for custom context data in feeds

Thanks Paul Winkler for the initial patch. (Ref #18112).
  • Loading branch information...
commit 0a8402eb052a5c35085baa5408aaf4ee36ebc0a6 1 parent 4506ae0
@zsiciarz zsiciarz authored jacobian committed
View
16 django/contrib/syndication/views.py
@@ -100,6 +100,16 @@ def item_extra_kwargs(self, item):
def get_object(self, request, *args, **kwargs):
return None
+ def get_context_data(self, **kwargs):
+ """
+ Returns a dictionary to use as extra context if either
+ ``self.description_template`` or ``self.item_template`` are used.
+
+ Default implementation preserves the old behavior
+ of using {'obj': item, 'site': current_site} as the context.
+ """
+ return {'obj': kwargs.get('item'), 'site': kwargs.get('site')}
+
def get_feed(self, obj, request):
"""
Returns a feedgenerator.DefaultFeed object, fully populated, for
@@ -146,12 +156,14 @@ def get_feed(self, obj, request):
pass
for item in self.__get_dynamic_attr('items', obj):
+ context = self.get_context_data(item=item, site=current_site,
+ obj=obj, request=request)
if title_tmp is not None:
- title = title_tmp.render(RequestContext(request, {'obj': item, 'site': current_site}))
+ title = title_tmp.render(RequestContext(request, context))
else:
title = self.__get_dynamic_attr('item_title', item)
if description_tmp is not None:
- description = description_tmp.render(RequestContext(request, {'obj': item, 'site': current_site}))
+ description = description_tmp.render(RequestContext(request, context))
else:
description = self.__get_dynamic_attr('item_description', item)
link = add_domain(
View
54 docs/ref/contrib/syndication.txt
@@ -137,6 +137,51 @@ into those elements.
See `a complex example`_ below that uses a description template.
+ There is also a way to pass additional information to title and description
+ templates, if you need to supply more than the two variables mentioned
+ before. You can provide your implementation of ``get_context_data`` method
+ in your Feed subclass. For example::
+
+ from mysite.models import Article
+ from django.contrib.syndication.views import Feed
+
+ class ArticlesFeed(Feed):
+ title = "My articles"
+ description_template = "feeds/articles.html"
+
+ def items(self):
+ return Article.objects.order_by('-pub_date')[:5]
+
+ def get_context_data(self, **kwargs):
+ context = super(ArticlesFeed, self).get_context_data(**kwargs)
+ context['foo'] = 'bar'
+ return context
+
+ And the template:
+
+ .. code-block:: html+django
+
+ Something about {{ foo }}: {{ obj.description }}
+
+ This method will be called once per each item in the list returned by
+ ``items()`` with the following keyword arguments:
+
+ * ``item``: the current item. For backward compatibility reasons, the name
+ of this context variable is ``{{ obj }}``.
+
+ * ``obj``: the object returned by ``get_object()``. By default this is not
+ exposed to the templates to avoid confusion with ``{{ obj }}`` (see above),
+ but you can use it in your implementation of ``get_context_data()``.
+
+ * ``site``: current site as described above.
+
+ * ``request``: current request.
+
+ The behavior of ``get_context_data()`` mimics that of
+ :ref:`generic views <adding-extra-context>` - you're supposed to call
+ ``super()`` to retrieve context data from parent class, add your data
+ and return the modified dictionary.
+
* To specify the contents of ``<link>``, you have two options. For each item
in ``items()``, Django first tries calling the
``item_link()`` method on the
@@ -599,6 +644,15 @@ This example illustrates all possible attributes and methods for a
item_description = 'A description of the item.' # Hard-coded description.
+ def get_context_data(self, **kwargs):
+ """
+ Returns a dictionary to use as extra context if either
+ description_template or item_template are used.
+
+ Default implementation preserves the old behavior
+ of using {'obj': item, 'site': current_site} as the context.
+ """
+
# ITEM LINK -- One of these three is required. The framework looks for
# them in this order.
View
2  docs/topics/class-based-views/generic-display.txt
@@ -188,6 +188,8 @@ Providing a useful ``context_object_name`` is always a good idea. Your
coworkers who design templates will thank you.
+.. _adding-extra-context:
+
Adding extra context
--------------------
View
13 tests/regressiontests/syndication/feeds.py
@@ -97,6 +97,19 @@ def item_title(self):
return "Not in a template"
+class TemplateContextFeed(TestRss2Feed):
+ """
+ A feed to test custom context data in templates for title or description.
+ """
+ title_template = 'syndication/title_context.html'
+ description_template = 'syndication/description_context.html'
+
+ def get_context_data(self, **kwargs):
+ context = super(TemplateContextFeed, self).get_context_data(**kwargs)
+ context['foo'] = 'bar'
+ return context
+
+
class NaiveDatesFeed(TestAtomFeed):
"""
A feed with naive (non-timezone-aware) dates.
View
1  tests/regressiontests/syndication/templates/syndication/description_context.html
@@ -0,0 +1 @@
+{{ obj }} (foo is {{ foo }})
View
1  tests/regressiontests/syndication/templates/syndication/title_context.html
@@ -0,0 +1 @@
+{{ obj }} (foo is {{ foo }})
View
16 tests/regressiontests/syndication/tests.py
@@ -323,6 +323,22 @@ def test_template_feed(self):
'link': 'http://example.com/blog/1/',
})
+ def test_template_context_feed(self):
+ """
+ Test that custom context data can be passed to templates for title
+ and description.
+ """
+ response = self.client.get('/syndication/template_context/')
+ doc = minidom.parseString(response.content)
+ feed = doc.getElementsByTagName('rss')[0]
+ chan = feed.getElementsByTagName('channel')[0]
+ items = chan.getElementsByTagName('item')
+
+ self.assertChildNodeContent(items[0], {
+ 'title': 'My first entry (foo is bar)',
+ 'description': 'My first entry (foo is bar)',
+ })
+
def test_add_domain(self):
"""
Test add_domain() prefixes domains onto the correct URLs.
View
1  tests/regressiontests/syndication/urls.py
@@ -21,4 +21,5 @@
(r'^syndication/feedurl/$', feeds.TestFeedUrlFeed()),
(r'^syndication/articles/$', feeds.ArticlesFeed()),
(r'^syndication/template/$', feeds.TemplateFeed()),
+ (r'^syndication/template_context/$', feeds.TemplateContextFeed()),
)
Please sign in to comment.
Something went wrong with that request. Please try again.