|
1 ============================== |
|
2 The syndication feed framework |
|
3 ============================== |
|
4 |
|
5 Django comes with a high-level syndication-feed-generating framework that makes |
|
6 creating RSS_ and Atom_ feeds easy. |
|
7 |
|
8 To create any syndication feed, all you have to do is write a short Python |
|
9 class. You can create as many feeds as you want. |
|
10 |
|
11 Django also comes with a lower-level feed-generating API. Use this if you want |
|
12 to generate feeds outside of a Web context, or in some other lower-level way. |
|
13 |
|
14 .. _RSS: http://www.whatisrss.com/ |
|
15 .. _Atom: http://www.atomenabled.org/ |
|
16 |
|
17 The high-level framework |
|
18 ======================== |
|
19 |
|
20 Overview |
|
21 -------- |
|
22 |
|
23 The high-level feed-generating framework is a view that's hooked to ``/feeds/`` |
|
24 by default. Django uses the remainder of the URL (everything after ``/feeds/``) |
|
25 to determine which feed to output. |
|
26 |
|
27 To create a feed, just write a ``Feed`` class and point to it in your URLconf_. |
|
28 |
|
29 .. _URLconf: ../url_dispatch/ |
|
30 |
|
31 Initialization |
|
32 -------------- |
|
33 |
|
34 To activate syndication feeds on your Django site, add this line to your |
|
35 URLconf_:: |
|
36 |
|
37 (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', {'feed_dict': feeds}), |
|
38 |
|
39 This tells Django to use the RSS framework to handle all URLs starting with |
|
40 ``"feeds/"``. (You can change that ``"feeds/"`` prefix to fit your own needs.) |
|
41 |
|
42 This URLconf line has an extra argument: ``{'feed_dict': feeds}``. Use this |
|
43 extra argument to pass the syndication framework the feeds that should be |
|
44 published under that URL. |
|
45 |
|
46 Specifically, ``feed_dict`` should be a dictionary that maps a feed's slug |
|
47 (short URL label) to its ``Feed`` class. |
|
48 |
|
49 You can define the ``feed_dict`` in the URLconf itself. Here's a full example |
|
50 URLconf:: |
|
51 |
|
52 from django.conf.urls.defaults import * |
|
53 from myproject.feeds import LatestEntries, LatestEntriesByCategory |
|
54 |
|
55 feeds = { |
|
56 'latest': LatestEntries, |
|
57 'categories': LatestEntriesByCategory, |
|
58 } |
|
59 |
|
60 urlpatterns = patterns('', |
|
61 # ... |
|
62 (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', |
|
63 {'feed_dict': feeds}), |
|
64 # ... |
|
65 ) |
|
66 |
|
67 The above example registers two feeds: |
|
68 |
|
69 * The feed represented by ``LatestEntries`` will live at ``feeds/latest/``. |
|
70 * The feed represented by ``LatestEntriesByCategory`` will live at |
|
71 ``feeds/categories/``. |
|
72 |
|
73 Once that's set up, you just need to define the ``Feed`` classes themselves. |
|
74 |
|
75 .. _URLconf: ../url_dispatch/ |
|
76 .. _settings file: ../settings/ |
|
77 |
|
78 Feed classes |
|
79 ------------ |
|
80 |
|
81 A ``Feed`` class is a simple Python class that represents a syndication feed. |
|
82 A feed can be simple (e.g., a "site news" feed, or a basic feed displaying |
|
83 the latest entries of a blog) or more complex (e.g., a feed displaying all the |
|
84 blog entries in a particular category, where the category is variable). |
|
85 |
|
86 ``Feed`` classes must subclass ``django.contrib.syndication.feeds.Feed``. They |
|
87 can live anywhere in your codebase. |
|
88 |
|
89 A simple example |
|
90 ---------------- |
|
91 |
|
92 This simple example, taken from `chicagocrime.org`_, describes a feed of the |
|
93 latest five news items:: |
|
94 |
|
95 from django.contrib.syndication.feeds import Feed |
|
96 from chicagocrime.models import NewsItem |
|
97 |
|
98 class LatestEntries(Feed): |
|
99 title = "Chicagocrime.org site news" |
|
100 link = "/sitenews/" |
|
101 description = "Updates on changes and additions to chicagocrime.org." |
|
102 |
|
103 def items(self): |
|
104 return NewsItem.objects.order_by('-pub_date')[:5] |
|
105 |
|
106 Note: |
|
107 |
|
108 * The class subclasses ``django.contrib.syndication.feeds.Feed``. |
|
109 * ``title``, ``link`` and ``description`` correspond to the standard |
|
110 RSS ``<title>``, ``<link>`` and ``<description>`` elements, respectively. |
|
111 * ``items()`` is, simply, a method that returns a list of objects that |
|
112 should be included in the feed as ``<item>`` elements. Although this |
|
113 example returns ``NewsItem`` objects using Django's |
|
114 `object-relational mapper`_, ``items()`` doesn't have to return model |
|
115 instances. Although you get a few bits of functionality "for free" by |
|
116 using Django models, ``items()`` can return any type of object you want. |
|
117 |
|
118 One thing's left to do. In an RSS feed, each ``<item>`` has a ``<title>``, |
|
119 ``<link>`` and ``<description>``. We need to tell the framework what data to |
|
120 put into those elements. |
|
121 |
|
122 * To specify the contents of ``<title>`` and ``<description>``, create |
|
123 `Django templates`_ called ``feeds/latest_title.html`` and |
|
124 ``feeds/latest_description.html``, where ``latest`` is the ``slug`` |
|
125 specified in the URLconf for the given feed. Note the ``.html`` extension |
|
126 is required. The RSS system renders that template for each item, passing |
|
127 it two template context variables: |
|
128 |
|
129 * ``{{ obj }}`` -- The current object (one of whichever objects you |
|
130 returned in ``items()``). |
|
131 * ``{{ site }}`` -- A ``django.models.core.sites.Site`` object |
|
132 representing the current site. This is useful for |
|
133 ``{{ site.domain }}`` or ``{{ site.name }}``. |
|
134 |
|
135 If you don't create a template for either the title or description, the |
|
136 framework will use the template ``"{{ obj }}"`` by default -- that is, |
|
137 the normal string representation of the object. You can also change the |
|
138 names of these two templates by specifying ``title_template`` and |
|
139 ``description_template`` as attributes of your ``Feed`` class. |
|
140 * To specify the contents of ``<link>``, you have two options. For each |
|
141 item in ``items()``, Django first tries executing a |
|
142 ``get_absolute_url()`` method on that object. If that method doesn't |
|
143 exist, it tries calling a method ``item_link()`` in the ``Feed`` class, |
|
144 passing it a single parameter, ``item``, which is the object itself. |
|
145 Both ``get_absolute_url()`` and ``item_link()`` should return the item's |
|
146 URL as a normal Python string. |
|
147 |
|
148 * For the LatestEntries example above, we could have very simple feed templates: |
|
149 |
|
150 * latest_title.html:: |
|
151 |
|
152 {{ obj.title }} |
|
153 |
|
154 * latest_description.html:: |
|
155 |
|
156 {{ obj.description }} |
|
157 |
|
158 .. _chicagocrime.org: http://www.chicagocrime.org/ |
|
159 .. _object-relational mapper: ../db_api/ |
|
160 .. _Django templates: ../templates/ |
|
161 |
|
162 A complex example |
|
163 ----------------- |
|
164 |
|
165 The framework also supports more complex feeds, via parameters. |
|
166 |
|
167 For example, `chicagocrime.org`_ offers an RSS feed of recent crimes for every |
|
168 police beat in Chicago. It'd be silly to create a separate ``Feed`` class for |
|
169 each police beat; that would violate the `DRY principle`_ and would couple data |
|
170 to programming logic. Instead, the syndication framework lets you make generic |
|
171 feeds that output items based on information in the feed's URL. |
|
172 |
|
173 On chicagocrime.org, the police-beat feeds are accessible via URLs like this: |
|
174 |
|
175 * ``/rss/beats/0613/`` -- Returns recent crimes for beat 0613. |
|
176 * ``/rss/beats/1424/`` -- Returns recent crimes for beat 1424. |
|
177 |
|
178 The slug here is ``"beats"``. The syndication framework sees the extra URL bits |
|
179 after the slug -- ``0613`` and ``1424`` -- and gives you a hook to tell it what |
|
180 those URL bits mean, and how they should influence which items get published in |
|
181 the feed. |
|
182 |
|
183 An example makes this clear. Here's the code for these beat-specific feeds:: |
|
184 |
|
185 class BeatFeed(Feed): |
|
186 def get_object(self, bits): |
|
187 # In case of "/rss/beats/0613/foo/bar/baz/", or other such clutter, |
|
188 # check that bits has only one member. |
|
189 if len(bits) != 1: |
|
190 raise ObjectDoesNotExist |
|
191 return Beat.objects.get(beat__exact=bits[0]) |
|
192 |
|
193 def title(self, obj): |
|
194 return "Chicagocrime.org: Crimes for beat %s" % obj.beat |
|
195 |
|
196 def link(self, obj): |
|
197 return obj.get_absolute_url() |
|
198 |
|
199 def description(self, obj): |
|
200 return "Crimes recently reported in police beat %s" % obj.beat |
|
201 |
|
202 def items(self, obj): |
|
203 return Crime.objects.filter(beat__id__exact=obj.id).order_by('-crime_date')[:30] |
|
204 |
|
205 Here's the basic algorithm the RSS framework follows, given this class and a |
|
206 request to the URL ``/rss/beats/0613/``: |
|
207 |
|
208 * The framework gets the URL ``/rss/beats/0613/`` and notices there's |
|
209 an extra bit of URL after the slug. It splits that remaining string by |
|
210 the slash character (``"/"``) and calls the ``Feed`` class' |
|
211 ``get_object()`` method, passing it the bits. In this case, bits is |
|
212 ``['0613']``. For a request to ``/rss/beats/0613/foo/bar/``, bits would |
|
213 be ``['0613', 'foo', 'bar']``. |
|
214 * ``get_object()`` is responsible for retrieving the given beat, from the |
|
215 given ``bits``. In this case, it uses the Django database API to retrieve |
|
216 the beat. Note that ``get_object()`` should raise |
|
217 ``django.core.exceptions.ObjectDoesNotExist`` if given invalid |
|
218 parameters. There's no ``try``/``except`` around the |
|
219 ``Beat.objects.get()`` call, because it's not necessary; that function |
|
220 raises ``Beat.DoesNotExist`` on failure, and ``Beat.DoesNotExist`` is a |
|
221 subclass of ``ObjectDoesNotExist``. Raising ``ObjectDoesNotExist`` in |
|
222 ``get_object()`` tells Django to produce a 404 error for that request. |
|
223 * To generate the feed's ``<title>``, ``<link>`` and ``<description>``, |
|
224 Django uses the ``title()``, ``link()`` and ``description()`` methods. In |
|
225 the previous example, they were simple string class attributes, but this |
|
226 example illustrates that they can be either strings *or* methods. For |
|
227 each of ``title``, ``link`` and ``description``, Django follows this |
|
228 algorithm: |
|
229 |
|
230 * First, it tries to call a method, passing the ``obj`` argument, where |
|
231 ``obj`` is the object returned by ``get_object()``. |
|
232 * Failing that, it tries to call a method with no arguments. |
|
233 * Failing that, it uses the class attribute. |
|
234 |
|
235 * Finally, note that ``items()`` in this example also takes the ``obj`` |
|
236 argument. The algorithm for ``items`` is the same as described in the |
|
237 previous step -- first, it tries ``items(obj)``, then ``items()``, then |
|
238 finally an ``items`` class attribute (which should be a list). |
|
239 |
|
240 The ``ExampleFeed`` class below gives full documentation on methods and |
|
241 attributes of ``Feed`` classes. |
|
242 |
|
243 .. _DRY principle: http://c2.com/cgi/wiki?DontRepeatYourself |
|
244 |
|
245 Specifying the type of feed |
|
246 --------------------------- |
|
247 |
|
248 By default, feeds produced in this framework use RSS 2.0. |
|
249 |
|
250 To change that, add a ``feed_type`` attribute to your ``Feed`` class, like so:: |
|
251 |
|
252 from django.utils.feedgenerator import Atom1Feed |
|
253 |
|
254 class MyFeed(Feed): |
|
255 feed_type = Atom1Feed |
|
256 |
|
257 Note that you set ``feed_type`` to a class object, not an instance. |
|
258 |
|
259 Currently available feed types are: |
|
260 |
|
261 * ``django.utils.feedgenerator.Rss201rev2Feed`` (RSS 2.01. Default.) |
|
262 * ``django.utils.feedgenerator.RssUserland091Feed`` (RSS 0.91.) |
|
263 * ``django.utils.feedgenerator.Atom1Feed`` (Atom 1.0.) |
|
264 |
|
265 Enclosures |
|
266 ---------- |
|
267 |
|
268 To specify enclosures, such as those used in creating podcast feeds, use the |
|
269 ``item_enclosure_url``, ``item_enclosure_length`` and |
|
270 ``item_enclosure_mime_type`` hooks. See the ``ExampleFeed`` class below for |
|
271 usage examples. |
|
272 |
|
273 Language |
|
274 -------- |
|
275 |
|
276 Feeds created by the syndication framework automatically include the |
|
277 appropriate ``<language>`` tag (RSS 2.0) or ``xml:lang`` attribute (Atom). This |
|
278 comes directly from your `LANGUAGE_CODE setting`_. |
|
279 |
|
280 .. _LANGUAGE_CODE setting: ../settings/#language-code |
|
281 |
|
282 URLs |
|
283 ---- |
|
284 |
|
285 The ``link`` method/attribute can return either an absolute URL (e.g. |
|
286 ``"/blog/"``) or a URL with the fully-qualified domain and protocol (e.g. |
|
287 ``"http://www.example.com/blog/"``). If ``link`` doesn't return the domain, |
|
288 the syndication framework will insert the domain of the current site, according |
|
289 to your `SITE_ID setting`_. |
|
290 |
|
291 Atom feeds require a ``<link rel="self">`` that defines the feed's current |
|
292 location. The syndication framework populates this automatically, using the |
|
293 domain of the current site according to the SITE_ID setting. |
|
294 |
|
295 .. _SITE_ID setting: ../settings/#site-id |
|
296 |
|
297 Publishing Atom and RSS feeds in tandem |
|
298 --------------------------------------- |
|
299 |
|
300 Some developers like to make available both Atom *and* RSS versions of their |
|
301 feeds. That's easy to do with Django: Just create a subclass of your ``feed`` |
|
302 class and set the ``feed_type`` to something different. Then update your |
|
303 URLconf to add the extra versions. |
|
304 |
|
305 Here's a full example:: |
|
306 |
|
307 from django.contrib.syndication.feeds import Feed |
|
308 from chicagocrime.models import NewsItem |
|
309 from django.utils.feedgenerator import Atom1Feed |
|
310 |
|
311 class RssSiteNewsFeed(Feed): |
|
312 title = "Chicagocrime.org site news" |
|
313 link = "/sitenews/" |
|
314 description = "Updates on changes and additions to chicagocrime.org." |
|
315 |
|
316 def items(self): |
|
317 return NewsItem.objects.order_by('-pub_date')[:5] |
|
318 |
|
319 class AtomSiteNewsFeed(RssSiteNewsFeed): |
|
320 feed_type = Atom1Feed |
|
321 |
|
322 And the accompanying URLconf:: |
|
323 |
|
324 from django.conf.urls.defaults import * |
|
325 from myproject.feeds import RssSiteNewsFeed, AtomSiteNewsFeed |
|
326 |
|
327 feeds = { |
|
328 'rss': RssSiteNewsFeed, |
|
329 'atom': AtomSiteNewsFeed, |
|
330 } |
|
331 |
|
332 urlpatterns = patterns('', |
|
333 # ... |
|
334 (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', |
|
335 {'feed_dict': feeds}), |
|
336 # ... |
|
337 ) |
|
338 |
|
339 Feed class reference |
|
340 -------------------- |
|
341 |
|
342 This example illustrates all possible attributes and methods for a ``Feed`` class:: |
|
343 |
|
344 from django.contrib.syndication.feeds import Feed |
|
345 from django.utils import feedgenerator |
|
346 |
|
347 class ExampleFeed(Feed): |
|
348 |
|
349 # FEED TYPE -- Optional. This should be a class that subclasses |
|
350 # django.utils.feedgenerator.SyndicationFeed. This designates which |
|
351 # type of feed this should be: RSS 2.0, Atom 1.0, etc. |
|
352 # If you don't specify feed_type, your feed will be RSS 2.0. |
|
353 # This should be a class, not an instance of the class. |
|
354 |
|
355 feed_type = feedgenerator.Rss201rev2Feed |
|
356 |
|
357 # TEMPLATE NAMES -- Optional. These should be strings representing |
|
358 # names of Django templates that the system should use in rendering the |
|
359 # title and description of your feed items. Both are optional. |
|
360 # If you don't specify one, or either, Django will use the template |
|
361 # 'feeds/SLUG_title.html' and 'feeds/SLUG_description.html', where SLUG |
|
362 # is the slug you specify in the URL. |
|
363 |
|
364 title_template = None |
|
365 description_template = None |
|
366 |
|
367 # TITLE -- One of the following three is required. The framework looks |
|
368 # for them in this order. |
|
369 |
|
370 def title(self, obj): |
|
371 """ |
|
372 Takes the object returned by get_object() and returns the feed's |
|
373 title as a normal Python string. |
|
374 """ |
|
375 |
|
376 def title(self): |
|
377 """ |
|
378 Returns the feed's title as a normal Python string. |
|
379 """ |
|
380 |
|
381 title = 'foo' # Hard-coded title. |
|
382 |
|
383 # LINK -- One of the following three is required. The framework looks |
|
384 # for them in this order. |
|
385 |
|
386 def link(self, obj): |
|
387 """ |
|
388 Takes the object returned by get_object() and returns the feed's |
|
389 link as a normal Python string. |
|
390 """ |
|
391 |
|
392 def link(self): |
|
393 """ |
|
394 Returns the feed's link as a normal Python string. |
|
395 """ |
|
396 |
|
397 link = '/foo/bar/' # Hard-coded link. |
|
398 |
|
399 # DESCRIPTION -- One of the following three is required. The framework |
|
400 # looks for them in this order. |
|
401 |
|
402 def description(self, obj): |
|
403 """ |
|
404 Takes the object returned by get_object() and returns the feed's |
|
405 description as a normal Python string. |
|
406 """ |
|
407 |
|
408 def description(self): |
|
409 """ |
|
410 Returns the feed's description as a normal Python string. |
|
411 """ |
|
412 |
|
413 description = 'Foo bar baz.' # Hard-coded description. |
|
414 |
|
415 # AUTHOR NAME --One of the following three is optional. The framework |
|
416 # looks for them in this order. |
|
417 |
|
418 def author_name(self, obj): |
|
419 """ |
|
420 Takes the object returned by get_object() and returns the feed's |
|
421 author's name as a normal Python string. |
|
422 """ |
|
423 |
|
424 def author_name(self): |
|
425 """ |
|
426 Returns the feed's author's name as a normal Python string. |
|
427 """ |
|
428 |
|
429 author_name = 'Sally Smith' # Hard-coded author name. |
|
430 |
|
431 # AUTHOR E-MAIL --One of the following three is optional. The framework |
|
432 # looks for them in this order. |
|
433 |
|
434 def author_email(self, obj): |
|
435 """ |
|
436 Takes the object returned by get_object() and returns the feed's |
|
437 author's e-mail as a normal Python string. |
|
438 """ |
|
439 |
|
440 def author_email(self): |
|
441 """ |
|
442 Returns the feed's author's e-mail as a normal Python string. |
|
443 """ |
|
444 |
|
445 author_email = 'test@example.com' # Hard-coded author e-mail. |
|
446 |
|
447 # AUTHOR LINK --One of the following three is optional. The framework |
|
448 # looks for them in this order. In each case, the URL should include |
|
449 # the "http://" and domain name. |
|
450 |
|
451 def author_link(self, obj): |
|
452 """ |
|
453 Takes the object returned by get_object() and returns the feed's |
|
454 author's URL as a normal Python string. |
|
455 """ |
|
456 |
|
457 def author_link(self): |
|
458 """ |
|
459 Returns the feed's author's URL as a normal Python string. |
|
460 """ |
|
461 |
|
462 author_link = 'http://www.example.com/' # Hard-coded author URL. |
|
463 |
|
464 # CATEGORIES -- One of the following three is optional. The framework |
|
465 # looks for them in this order. In each case, the method/attribute |
|
466 # should return an iterable object that returns strings. |
|
467 |
|
468 def categories(self, obj): |
|
469 """ |
|
470 Takes the object returned by get_object() and returns the feed's |
|
471 categories as iterable over strings. |
|
472 """ |
|
473 |
|
474 def categories(self): |
|
475 """ |
|
476 Returns the feed's categories as iterable over strings. |
|
477 """ |
|
478 |
|
479 categories = ("python", "django") # Hard-coded list of categories. |
|
480 |
|
481 # COPYRIGHT NOTICE -- One of the following three is optional. The |
|
482 # framework looks for them in this order. |
|
483 |
|
484 def copyright(self, obj): |
|
485 """ |
|
486 Takes the object returned by get_object() and returns the feed's |
|
487 copyright notice as a normal Python string. |
|
488 """ |
|
489 |
|
490 def copyright(self): |
|
491 """ |
|
492 Returns the feed's copyright notice as a normal Python string. |
|
493 """ |
|
494 |
|
495 copyright = 'Copyright (c) 2007, Sally Smith' # Hard-coded copyright notice. |
|
496 |
|
497 # ITEMS -- One of the following three is required. The framework looks |
|
498 # for them in this order. |
|
499 |
|
500 def items(self, obj): |
|
501 """ |
|
502 Takes the object returned by get_object() and returns a list of |
|
503 items to publish in this feed. |
|
504 """ |
|
505 |
|
506 def items(self): |
|
507 """ |
|
508 Returns a list of items to publish in this feed. |
|
509 """ |
|
510 |
|
511 items = ('Item 1', 'Item 2') # Hard-coded items. |
|
512 |
|
513 # GET_OBJECT -- This is required for feeds that publish different data |
|
514 # for different URL parameters. (See "A complex example" above.) |
|
515 |
|
516 def get_object(self, bits): |
|
517 """ |
|
518 Takes a list of strings gleaned from the URL and returns an object |
|
519 represented by this feed. Raises |
|
520 django.core.exceptions.ObjectDoesNotExist on error. |
|
521 """ |
|
522 |
|
523 # ITEM LINK -- One of these three is required. The framework looks for |
|
524 # them in this order. |
|
525 |
|
526 # First, the framework tries the get_absolute_url() method on each item |
|
527 # returned by items(). Failing that, it tries these two methods: |
|
528 |
|
529 def item_link(self, item): |
|
530 """ |
|
531 Takes an item, as returned by items(), and returns the item's URL. |
|
532 """ |
|
533 |
|
534 def item_link(self): |
|
535 """ |
|
536 Returns the URL for every item in the feed. |
|
537 """ |
|
538 |
|
539 # ITEM AUTHOR NAME --One of the following three is optional. The |
|
540 # framework looks for them in this order. |
|
541 |
|
542 def item_author_name(self, item): |
|
543 """ |
|
544 Takes an item, as returned by items(), and returns the item's |
|
545 author's name as a normal Python string. |
|
546 """ |
|
547 |
|
548 def item_author_name(self): |
|
549 """ |
|
550 Returns the author name for every item in the feed. |
|
551 """ |
|
552 |
|
553 item_author_name = 'Sally Smith' # Hard-coded author name. |
|
554 |
|
555 # ITEM AUTHOR E-MAIL --One of the following three is optional. The |
|
556 # framework looks for them in this order. |
|
557 # |
|
558 # If you specify this, you must specify item_author_name. |
|
559 |
|
560 def item_author_email(self, obj): |
|
561 """ |
|
562 Takes an item, as returned by items(), and returns the item's |
|
563 author's e-mail as a normal Python string. |
|
564 """ |
|
565 |
|
566 def item_author_email(self): |
|
567 """ |
|
568 Returns the author e-mail for every item in the feed. |
|
569 """ |
|
570 |
|
571 item_author_email = 'test@example.com' # Hard-coded author e-mail. |
|
572 |
|
573 # ITEM AUTHOR LINK --One of the following three is optional. The |
|
574 # framework looks for them in this order. In each case, the URL should |
|
575 # include the "http://" and domain name. |
|
576 # |
|
577 # If you specify this, you must specify item_author_name. |
|
578 |
|
579 def item_author_link(self, obj): |
|
580 """ |
|
581 Takes an item, as returned by items(), and returns the item's |
|
582 author's URL as a normal Python string. |
|
583 """ |
|
584 |
|
585 def item_author_link(self): |
|
586 """ |
|
587 Returns the author URL for every item in the feed. |
|
588 """ |
|
589 |
|
590 item_author_link = 'http://www.example.com/' # Hard-coded author URL. |
|
591 |
|
592 # ITEM ENCLOSURE URL -- One of these three is required if you're |
|
593 # publishing enclosures. The framework looks for them in this order. |
|
594 |
|
595 def item_enclosure_url(self, item): |
|
596 """ |
|
597 Takes an item, as returned by items(), and returns the item's |
|
598 enclosure URL. |
|
599 """ |
|
600 |
|
601 def item_enclosure_url(self): |
|
602 """ |
|
603 Returns the enclosure URL for every item in the feed. |
|
604 """ |
|
605 |
|
606 item_enclosure_url = "/foo/bar.mp3" # Hard-coded enclosure link. |
|
607 |
|
608 # ITEM ENCLOSURE LENGTH -- One of these three is required if you're |
|
609 # publishing enclosures. The framework looks for them in this order. |
|
610 # In each case, the returned value should be either an integer, or a |
|
611 # string representation of the integer, in bytes. |
|
612 |
|
613 def item_enclosure_length(self, item): |
|
614 """ |
|
615 Takes an item, as returned by items(), and returns the item's |
|
616 enclosure length. |
|
617 """ |
|
618 |
|
619 def item_enclosure_length(self): |
|
620 """ |
|
621 Returns the enclosure length for every item in the feed. |
|
622 """ |
|
623 |
|
624 item_enclosure_length = 32000 # Hard-coded enclosure length. |
|
625 |
|
626 # ITEM ENCLOSURE MIME TYPE -- One of these three is required if you're |
|
627 # publishing enclosures. The framework looks for them in this order. |
|
628 |
|
629 def item_enclosure_mime_type(self, item): |
|
630 """ |
|
631 Takes an item, as returned by items(), and returns the item's |
|
632 enclosure mime type. |
|
633 """ |
|
634 |
|
635 def item_enclosure_mime_type(self): |
|
636 """ |
|
637 Returns the enclosure length, in bytes, for every item in the feed. |
|
638 """ |
|
639 |
|
640 item_enclosure_mime_type = "audio/mpeg" # Hard-coded enclosure mime-type. |
|
641 |
|
642 # ITEM PUBDATE -- It's optional to use one of these three. This is a |
|
643 # hook that specifies how to get the pubdate for a given item. |
|
644 # In each case, the method/attribute should return a Python |
|
645 # datetime.datetime object. |
|
646 |
|
647 def item_pubdate(self, item): |
|
648 """ |
|
649 Takes an item, as returned by items(), and returns the item's |
|
650 pubdate. |
|
651 """ |
|
652 |
|
653 def item_pubdate(self): |
|
654 """ |
|
655 Returns the pubdate for every item in the feed. |
|
656 """ |
|
657 |
|
658 item_pubdate = datetime.datetime(2005, 5, 3) # Hard-coded pubdate. |
|
659 |
|
660 # ITEM CATEGORIES -- It's optional to use one of these three. This is |
|
661 # a hook that specifies how to get the list of categories for a given |
|
662 # item. In each case, the method/attribute should return an iterable |
|
663 # object that returns strings. |
|
664 |
|
665 def item_categories(self, item): |
|
666 """ |
|
667 Takes an item, as returned by items(), and returns the item's |
|
668 categories. |
|
669 """ |
|
670 |
|
671 def item_categories(self): |
|
672 """ |
|
673 Returns the categories for every item in the feed. |
|
674 """ |
|
675 |
|
676 item_categories = ("python", "django") # Hard-coded categories. |
|
677 |
|
678 # ITEM COPYRIGHT NOTICE (only applicable to Atom feeds) -- One of the |
|
679 # following three is optional. The framework looks for them in this |
|
680 # order. |
|
681 |
|
682 def item_copyright(self, obj): |
|
683 """ |
|
684 Takes an item, as returned by items(), and returns the item's |
|
685 copyright notice as a normal Python string. |
|
686 """ |
|
687 |
|
688 def item_copyright(self): |
|
689 """ |
|
690 Returns the copyright notice for every item in the feed. |
|
691 """ |
|
692 |
|
693 item_copyright = 'Copyright (c) 2007, Sally Smith' # Hard-coded copyright notice. |
|
694 |
|
695 |
|
696 The low-level framework |
|
697 ======================= |
|
698 |
|
699 Behind the scenes, the high-level RSS framework uses a lower-level framework |
|
700 for generating feeds' XML. This framework lives in a single module: |
|
701 `django/utils/feedgenerator.py`_. |
|
702 |
|
703 Feel free to use this framework on your own, for lower-level tasks. |
|
704 |
|
705 The ``feedgenerator`` module contains a base class ``SyndicationFeed`` and |
|
706 several subclasses: |
|
707 |
|
708 * ``RssUserland091Feed`` |
|
709 * ``Rss201rev2Feed`` |
|
710 * ``Atom1Feed`` |
|
711 |
|
712 Each of these three classes knows how to render a certain type of feed as XML. |
|
713 They share this interface: |
|
714 |
|
715 ``__init__(title, link, description, language=None, author_email=None,`` |
|
716 ``author_name=None, author_link=None, subtitle=None, categories=None,`` |
|
717 ``feed_url=None)`` |
|
718 |
|
719 Initializes the feed with the given metadata, which applies to the entire feed |
|
720 (i.e., not just to a specific item in the feed). |
|
721 |
|
722 All parameters, if given, should be Unicode objects, except ``categories``, |
|
723 which should be a sequence of Unicode objects. |
|
724 |
|
725 ``add_item(title, link, description, author_email=None, author_name=None,`` |
|
726 ``pubdate=None, comments=None, unique_id=None, enclosure=None, categories=())`` |
|
727 |
|
728 Add an item to the feed with the given parameters. All parameters, if given, |
|
729 should be Unicode objects, except: |
|
730 |
|
731 * ``pubdate`` should be a `Python datetime object`_. |
|
732 * ``enclosure`` should be an instance of ``feedgenerator.Enclosure``. |
|
733 * ``categories`` should be a sequence of Unicode objects. |
|
734 |
|
735 ``write(outfile, encoding)`` |
|
736 |
|
737 Outputs the feed in the given encoding to outfile, which is a file-like object. |
|
738 |
|
739 ``writeString(encoding)`` |
|
740 |
|
741 Returns the feed as a string in the given encoding. |
|
742 |
|
743 Example usage |
|
744 ------------- |
|
745 |
|
746 This example creates an Atom 1.0 feed and prints it to standard output:: |
|
747 |
|
748 >>> from django.utils import feedgenerator |
|
749 >>> f = feedgenerator.Atom1Feed( |
|
750 ... title=u"My Weblog", |
|
751 ... link=u"http://www.example.com/", |
|
752 ... description=u"In which I write about what I ate today.", |
|
753 ... language=u"en") |
|
754 >>> f.add_item(title=u"Hot dog today", |
|
755 ... link=u"http://www.example.com/entries/1/", |
|
756 ... description=u"<p>Today I had a Vienna Beef hot dog. It was pink, plump and perfect.</p>") |
|
757 >>> print f.writeString('utf8') |
|
758 <?xml version="1.0" encoding="utf8"?> |
|
759 <feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><title>My Weblog</title> |
|
760 <link href="http://www.example.com/"></link><id>http://www.example.com/</id> |
|
761 <updated>Sat, 12 Nov 2005 00:28:43 -0000</updated><entry><title>Hot dog today</title> |
|
762 <link>http://www.example.com/entries/1/</link><id>tag:www.example.com/entries/1/</id> |
|
763 <summary type="html"><p>Today I had a Vienna Beef hot dog. It was pink, plump and perfect.</p></summary> |
|
764 </entry></feed> |
|
765 |
|
766 .. _django/utils/feedgenerator.py: http://code.djangoproject.com/browser/django/trunk/django/utils/feedgenerator.py |
|
767 .. _Python datetime object: http://www.python.org/doc/current/lib/module-datetime.html |