summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Siciarz <antyqjon@gmail.com>2013-02-24 15:00:34 +0100
committerJacob Kaplan-Moss <jacob@jacobian.org>2013-02-24 08:33:20 -0600
commit0a8402eb052a5c35085baa5408aaf4ee36ebc0a6 (patch)
treeda243369985c25bd5b0a34e17560c81036317e16
parent4506ae0497d388f8bc118b9f6f916a5da48d599a (diff)
Test case and docs for custom context data in feeds
Thanks Paul Winkler for the initial patch. (Ref #18112).
-rw-r--r--django/contrib/syndication/views.py16
-rw-r--r--docs/ref/contrib/syndication.txt54
-rw-r--r--docs/topics/class-based-views/generic-display.txt2
-rw-r--r--tests/regressiontests/syndication/feeds.py13
-rw-r--r--tests/regressiontests/syndication/templates/syndication/description_context.html1
-rw-r--r--tests/regressiontests/syndication/templates/syndication/title_context.html1
-rw-r--r--tests/regressiontests/syndication/tests.py16
-rw-r--r--tests/regressiontests/syndication/urls.py1
8 files changed, 102 insertions, 2 deletions
diff --git a/django/contrib/syndication/views.py b/django/contrib/syndication/views.py
index a80b9d1fae..4abf1e53a9 100644
--- a/django/contrib/syndication/views.py
+++ b/django/contrib/syndication/views.py
@@ -100,6 +100,16 @@ class Feed(object):
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 @@ class Feed(object):
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(
diff --git a/docs/ref/contrib/syndication.txt b/docs/ref/contrib/syndication.txt
index 65aa7b57b4..02159c415b 100644
--- a/docs/ref/contrib/syndication.txt
+++ b/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.
diff --git a/docs/topics/class-based-views/generic-display.txt b/docs/topics/class-based-views/generic-display.txt
index 8fe6cd0d65..8695af7fe6 100644
--- a/docs/topics/class-based-views/generic-display.txt
+++ b/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
--------------------
diff --git a/tests/regressiontests/syndication/feeds.py b/tests/regressiontests/syndication/feeds.py
index 25757057b9..0956820bf0 100644
--- a/tests/regressiontests/syndication/feeds.py
+++ b/tests/regressiontests/syndication/feeds.py
@@ -97,6 +97,19 @@ class TemplateFeed(TestRss2Feed):
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.
diff --git a/tests/regressiontests/syndication/templates/syndication/description_context.html b/tests/regressiontests/syndication/templates/syndication/description_context.html
new file mode 100644
index 0000000000..319d84b1b0
--- /dev/null
+++ b/tests/regressiontests/syndication/templates/syndication/description_context.html
@@ -0,0 +1 @@
+{{ obj }} (foo is {{ foo }}) \ No newline at end of file
diff --git a/tests/regressiontests/syndication/templates/syndication/title_context.html b/tests/regressiontests/syndication/templates/syndication/title_context.html
new file mode 100644
index 0000000000..319d84b1b0
--- /dev/null
+++ b/tests/regressiontests/syndication/templates/syndication/title_context.html
@@ -0,0 +1 @@
+{{ obj }} (foo is {{ foo }}) \ No newline at end of file
diff --git a/tests/regressiontests/syndication/tests.py b/tests/regressiontests/syndication/tests.py
index 8885dc28c0..e8fc6be420 100644
--- a/tests/regressiontests/syndication/tests.py
+++ b/tests/regressiontests/syndication/tests.py
@@ -323,6 +323,22 @@ class SyndicationFeedTest(FeedTestCase):
'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.
diff --git a/tests/regressiontests/syndication/urls.py b/tests/regressiontests/syndication/urls.py
index ec3c8cc596..1dd7e92332 100644
--- a/tests/regressiontests/syndication/urls.py
+++ b/tests/regressiontests/syndication/urls.py
@@ -21,4 +21,5 @@ urlpatterns = patterns('django.contrib.syndication.views',
(r'^syndication/feedurl/$', feeds.TestFeedUrlFeed()),
(r'^syndication/articles/$', feeds.ArticlesFeed()),
(r'^syndication/template/$', feeds.TemplateFeed()),
+ (r'^syndication/template_context/$', feeds.TemplateContextFeed()),
)