Test case and docs for custom context data in feeds
Thanks Paul Winkler for the initial patch. (Ref #18112).
This commit is contained in:
parent
4506ae0497
commit
0a8402eb05
|
@ -100,6 +100,16 @@ class Feed(object):
|
||||||
def get_object(self, request, *args, **kwargs):
|
def get_object(self, request, *args, **kwargs):
|
||||||
return None
|
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):
|
def get_feed(self, obj, request):
|
||||||
"""
|
"""
|
||||||
Returns a feedgenerator.DefaultFeed object, fully populated, for
|
Returns a feedgenerator.DefaultFeed object, fully populated, for
|
||||||
|
@ -146,12 +156,14 @@ class Feed(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for item in self.__get_dynamic_attr('items', obj):
|
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:
|
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:
|
else:
|
||||||
title = self.__get_dynamic_attr('item_title', item)
|
title = self.__get_dynamic_attr('item_title', item)
|
||||||
if description_tmp is not None:
|
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:
|
else:
|
||||||
description = self.__get_dynamic_attr('item_description', item)
|
description = self.__get_dynamic_attr('item_description', item)
|
||||||
link = add_domain(
|
link = add_domain(
|
||||||
|
|
|
@ -137,6 +137,51 @@ into those elements.
|
||||||
|
|
||||||
See `a complex example`_ below that uses a description template.
|
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
|
* To specify the contents of ``<link>``, you have two options. For each item
|
||||||
in ``items()``, Django first tries calling the
|
in ``items()``, Django first tries calling the
|
||||||
``item_link()`` method on 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.
|
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
|
# ITEM LINK -- One of these three is required. The framework looks for
|
||||||
# them in this order.
|
# them in this order.
|
||||||
|
|
||||||
|
|
|
@ -188,6 +188,8 @@ Providing a useful ``context_object_name`` is always a good idea. Your
|
||||||
coworkers who design templates will thank you.
|
coworkers who design templates will thank you.
|
||||||
|
|
||||||
|
|
||||||
|
.. _adding-extra-context:
|
||||||
|
|
||||||
Adding extra context
|
Adding extra context
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,19 @@ class TemplateFeed(TestRss2Feed):
|
||||||
return "Not in a template"
|
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):
|
class NaiveDatesFeed(TestAtomFeed):
|
||||||
"""
|
"""
|
||||||
A feed with naive (non-timezone-aware) dates.
|
A feed with naive (non-timezone-aware) dates.
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{{ obj }} (foo is {{ foo }})
|
|
@ -0,0 +1 @@
|
||||||
|
{{ obj }} (foo is {{ foo }})
|
|
@ -323,6 +323,22 @@ class SyndicationFeedTest(FeedTestCase):
|
||||||
'link': 'http://example.com/blog/1/',
|
'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):
|
def test_add_domain(self):
|
||||||
"""
|
"""
|
||||||
Test add_domain() prefixes domains onto the correct URLs.
|
Test add_domain() prefixes domains onto the correct URLs.
|
||||||
|
|
|
@ -21,4 +21,5 @@ urlpatterns = patterns('django.contrib.syndication.views',
|
||||||
(r'^syndication/feedurl/$', feeds.TestFeedUrlFeed()),
|
(r'^syndication/feedurl/$', feeds.TestFeedUrlFeed()),
|
||||||
(r'^syndication/articles/$', feeds.ArticlesFeed()),
|
(r'^syndication/articles/$', feeds.ArticlesFeed()),
|
||||||
(r'^syndication/template/$', feeds.TemplateFeed()),
|
(r'^syndication/template/$', feeds.TemplateFeed()),
|
||||||
|
(r'^syndication/template_context/$', feeds.TemplateContextFeed()),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue