Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
Zbigniew Siciarz authored February 24, 2013 jacobian committed February 24, 2013
16  django/contrib/syndication/views.py
@@ -100,6 +100,16 @@ def item_extra_kwargs(self, item):
100 100
     def get_object(self, request, *args, **kwargs):
101 101
         return None
102 102
 
  103
+    def get_context_data(self, **kwargs):
  104
+        """
  105
+        Returns a dictionary to use as extra context if either
  106
+        ``self.description_template`` or ``self.item_template`` are used.
  107
+
  108
+        Default implementation preserves the old behavior
  109
+        of using {'obj': item, 'site': current_site} as the context.
  110
+        """
  111
+        return {'obj': kwargs.get('item'), 'site': kwargs.get('site')}
  112
+
103 113
     def get_feed(self, obj, request):
104 114
         """
105 115
         Returns a feedgenerator.DefaultFeed object, fully populated, for
@@ -146,12 +156,14 @@ def get_feed(self, obj, request):
146 156
                 pass
147 157
 
148 158
         for item in self.__get_dynamic_attr('items', obj):
  159
+            context = self.get_context_data(item=item, site=current_site,
  160
+                                            obj=obj, request=request)
149 161
             if title_tmp is not None:
150  
-                title = title_tmp.render(RequestContext(request, {'obj': item, 'site': current_site}))
  162
+                title = title_tmp.render(RequestContext(request, context))
151 163
             else:
152 164
                 title = self.__get_dynamic_attr('item_title', item)
153 165
             if description_tmp is not None:
154  
-                description = description_tmp.render(RequestContext(request, {'obj': item, 'site': current_site}))
  166
+                description = description_tmp.render(RequestContext(request, context))
155 167
             else:
156 168
                 description = self.__get_dynamic_attr('item_description', item)
157 169
             link = add_domain(
54  docs/ref/contrib/syndication.txt
@@ -137,6 +137,51 @@ into those elements.
137 137
 
138 138
   See `a complex example`_ below that uses a description template.
139 139
 
  140
+  There is also a way to pass additional information to title and description
  141
+  templates, if you need to supply more than the two variables mentioned
  142
+  before. You can provide your implementation of ``get_context_data`` method
  143
+  in your Feed subclass. For example::
  144
+
  145
+    from mysite.models import Article
  146
+    from django.contrib.syndication.views import Feed
  147
+
  148
+    class ArticlesFeed(Feed):
  149
+        title = "My articles"
  150
+        description_template = "feeds/articles.html"
  151
+
  152
+        def items(self):
  153
+            return Article.objects.order_by('-pub_date')[:5]
  154
+
  155
+        def get_context_data(self, **kwargs):
  156
+            context = super(ArticlesFeed, self).get_context_data(**kwargs)
  157
+            context['foo'] = 'bar'
  158
+            return context
  159
+
  160
+  And the template:
  161
+
  162
+  .. code-block:: html+django
  163
+
  164
+    Something about {{ foo }}: {{ obj.description }}
  165
+
  166
+  This method will be called once per each item in the list returned by
  167
+  ``items()`` with the following keyword arguments:
  168
+
  169
+  * ``item``: the current item. For backward compatibility reasons, the name
  170
+    of this context variable is ``{{ obj }}``.
  171
+
  172
+  * ``obj``: the object returned by ``get_object()``. By default this is not
  173
+    exposed to the templates to avoid confusion with ``{{ obj }}`` (see above),
  174
+    but you can use it in your implementation of ``get_context_data()``.
  175
+
  176
+  * ``site``: current site as described above.
  177
+
  178
+  * ``request``: current request.
  179
+
  180
+  The behavior of ``get_context_data()`` mimics that of
  181
+  :ref:`generic views <adding-extra-context>` - you're supposed to call
  182
+  ``super()`` to retrieve context data from parent class, add your data
  183
+  and return the modified dictionary.
  184
+
140 185
 * To specify the contents of ``<link>``, you have two options. For each item
141 186
   in ``items()``, Django first tries calling the
142 187
   ``item_link()`` method on the
@@ -599,6 +644,15 @@ This example illustrates all possible attributes and methods for a
599 644
 
600 645
         item_description = 'A description of the item.' # Hard-coded description.
601 646
 
  647
+        def get_context_data(self, **kwargs):
  648
+            """
  649
+            Returns a dictionary to use as extra context if either
  650
+            description_template or item_template are used.
  651
+
  652
+            Default implementation preserves the old behavior
  653
+            of using {'obj': item, 'site': current_site} as the context.
  654
+            """
  655
+
602 656
         # ITEM LINK -- One of these three is required. The framework looks for
603 657
         # them in this order.
604 658
 
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
188 188
 coworkers who design templates will thank you.
189 189
 
190 190
 
  191
+.. _adding-extra-context:
  192
+
191 193
 Adding extra context
192 194
 --------------------
193 195
 
13  tests/regressiontests/syndication/feeds.py
@@ -97,6 +97,19 @@ def item_title(self):
97 97
         return "Not in a template"
98 98
 
99 99
 
  100
+class TemplateContextFeed(TestRss2Feed):
  101
+    """
  102
+    A feed to test custom context data in templates for title or description.
  103
+    """
  104
+    title_template = 'syndication/title_context.html'
  105
+    description_template = 'syndication/description_context.html'
  106
+
  107
+    def get_context_data(self, **kwargs):
  108
+        context = super(TemplateContextFeed, self).get_context_data(**kwargs)
  109
+        context['foo'] = 'bar'
  110
+        return context
  111
+
  112
+
100 113
 class NaiveDatesFeed(TestAtomFeed):
101 114
     """
102 115
     A feed with naive (non-timezone-aware) dates.
1  tests/regressiontests/syndication/templates/syndication/description_context.html
... ...
@@ -0,0 +1 @@
  1
+{{ obj }} (foo is {{ foo }})
1  tests/regressiontests/syndication/templates/syndication/title_context.html
... ...
@@ -0,0 +1 @@
  1
+{{ obj }} (foo is {{ foo }})
16  tests/regressiontests/syndication/tests.py
@@ -323,6 +323,22 @@ def test_template_feed(self):
323 323
             'link': 'http://example.com/blog/1/',
324 324
         })
325 325
 
  326
+    def test_template_context_feed(self):
  327
+        """
  328
+        Test that custom context data can be passed to templates for title
  329
+        and description.
  330
+        """
  331
+        response = self.client.get('/syndication/template_context/')
  332
+        doc = minidom.parseString(response.content)
  333
+        feed = doc.getElementsByTagName('rss')[0]
  334
+        chan = feed.getElementsByTagName('channel')[0]
  335
+        items = chan.getElementsByTagName('item')
  336
+
  337
+        self.assertChildNodeContent(items[0], {
  338
+            'title': 'My first entry (foo is bar)',
  339
+            'description': 'My first entry (foo is bar)',
  340
+        })
  341
+
326 342
     def test_add_domain(self):
327 343
         """
328 344
         Test add_domain() prefixes domains onto the correct URLs.
1  tests/regressiontests/syndication/urls.py
@@ -21,4 +21,5 @@
21 21
     (r'^syndication/feedurl/$', feeds.TestFeedUrlFeed()),
22 22
     (r'^syndication/articles/$', feeds.ArticlesFeed()),
23 23
     (r'^syndication/template/$', feeds.TemplateFeed()),
  24
+    (r'^syndication/template_context/$', feeds.TemplateContextFeed()),
24 25
 )

0 notes on commit 0a8402e

Please sign in to comment.
Something went wrong with that request. Please try again.