Skip to content
Newer
Older
100644 990 lines (718 sloc) 35.7 KB
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
1 =======================================
2 Chapter 13: Generating Non-HTML Content
3 =======================================
4
5 Usually when we talk about developing Web sites, we're talking about producing
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
6 HTML. Of course, there's a lot more to the Web than HTML; we use the Web
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
7 to distribute data in all sorts of formats: RSS, PDFs, images, and so forth.
8
9 So far, we've focused on the common case of HTML production, but in this chapter
10 we'll take a detour and look at using Django to produce other types of content.
11
12 Django has convenient built-in tools that you can use to produce some common
13 non-HTML content:
14
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
15 * RSS/Atom syndication feeds
16
17 * Sitemaps (an XML format originally developed by Google that gives hints to
18 search engines)
19
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
20 We'll examine each of those tools a little later, but first we'll cover the
21 basic principles.
22
23 The basics: views and MIME-types
24 ================================
25
26 Recall from Chapter 3 that a view function is simply a Python function that
27 takes a Web request and returns a Web response. This response can be the HTML
28 contents of a Web page, or a redirect, or a 404 error, or an XML document,
29 or an image...or anything, really.
30
31 More formally, a Django view function *must*
32
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
33 * Accept an ``HttpRequest`` instance as its first argument
34
35 * Return an ``HttpResponse`` instance
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
36
37 The key to returning non-HTML content from a view lies in the ``HttpResponse``
38 class, specifically the ``mimetype`` argument. By tweaking the MIME type, we
39 can indicate to the browser that we've returned a response of a different
40 format.
41
42 For example, let's look at a view that returns a PNG image. To
43 keep things simple, we'll just read the file off the disk::
44
45 from django.http import HttpResponse
46
47 def my_image(request):
48 image_data = open("/path/to/my/image.png", "rb").read()
49 return HttpResponse(image_data, mimetype="image/png")
50
51 .. SL Tested ok
52
53 That's it! If you replace the image path in the ``open()`` call with a path to
54 a real image, you can use this very simple view to serve an image, and the
55 browser will display it correctly.
56
57 The other important thing to keep in mind is that ``HttpResponse`` objects
58 implement Python's standard "file-like object" API. This means that you can use
59 an ``HttpResponse`` instance in any place Python (or a third-party library)
60 expects a file.
61
62 For an example of how that works, let's take a look at producing CSV with
63 Django.
64
65 Producing CSV
66 =============
67
68 CSV is a simple data format usually used by spreadsheet software. It's basically
69 a series of table rows, with each cell in the row separated by a comma (CSV
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
70 stands for *comma-separated values*). For example, here's some data on "unruly"
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
71 airline passengers in CSV format::
72
73 Year,Unruly Airline Passengers
74 1995,146
75 1996,184
76 1997,235
77 1998,200
78 1999,226
79 2000,251
80 2001,299
81 2002,273
82 2003,281
83 2004,304
84 2005,203
85 2006,134
86 2007,147
87
88 .. note::
89
90 The preceding listing contains real numbers! They come from the U.S.
91 Federal Aviation Administration.
92
93 Though CSV looks simple, its formatting details haven't been universally agreed
94 upon. Different pieces of software produce and consume different variants of
95 CSV, making it a bit tricky to use. Luckily, Python comes with a standard CSV
96 library, ``csv``, that is pretty much bulletproof.
97
98 Because the ``csv`` module operates on file-like objects, it's a snap to use
99 an ``HttpResponse`` instead::
100
101 import csv
102 from django.http import HttpResponse
103
104 # Number of unruly passengers each year 1995 - 2005. In a real application
105 # this would likely come from a database or some other back-end data store.
106 UNRULY_PASSENGERS = [146,184,235,200,226,251,299,273,281,304,203]
107
108 def unruly_passengers_csv(request):
109 # Create the HttpResponse object with the appropriate CSV header.
110 response = HttpResponse(mimetype='text/csv')
111 response['Content-Disposition'] = 'attachment; filename=unruly.csv'
112
113 # Create the CSV writer using the HttpResponse as the "file."
114 writer = csv.writer(response)
115 writer.writerow(['Year', 'Unruly Airline Passengers'])
116 for (year, num) in zip(range(1995, 2006), UNRULY_PASSENGERS):
117 writer.writerow([year, num])
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
118
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
119 return response
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
120
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
121 .. SL Tested ok
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
122
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
123 The code and comments should be pretty clear, but a few things deserve special
124 mention:
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
125
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
126 * The response is given the ``text/csv`` MIME type (instead of the default
127 ``text/html``). This tells browsers that the document is a CSV file.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
128
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
129 * The response gets an additional ``Content-Disposition`` header, which
130 contains the name of the CSV file. This header (well, the "attachment"
131 part) will instruct the browser to prompt for a location to save the
132 file instead of just displaying it. This file name is arbitrary; call
133 it whatever you want. It will be used by browsers in the "Save As"
134 dialog.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
135
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
136 To assign a header on an ``HttpResponse``, just treat the
137 ``HttpResponse`` as a dictionary and set a key/value.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
138
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
139 * Hooking into the CSV-generation API is easy: just pass ``response`` as
140 the first argument to ``csv.writer``. The ``csv.writer`` function
141 expects a file-like object, and ``HttpResponse`` objects fit the bill.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
142
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
143 * For each row in your CSV file, call ``writer.writerow``, passing it an
144 iterable object such as a list or tuple.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
145
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
146 * The CSV module takes care of quoting for you, so you don't have to worry
147 about escaping strings with quotes or commas in them. Just pass
148 information to ``writerow()``, and it will do the right thing.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
149
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
150 This is the general pattern you'll use any time you need to return non-HTML
151 content: create an ``HttpResponse`` response object (with a special MIME type),
152 pass it to something expecting a file, and then return the response.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
153
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
154 Let's look at a few more examples.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
155
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
156 Generating PDFs
157 ===============
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
158
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
159 Portable Document Format (PDF) is a format developed by Adobe that's used to
160 represent printable documents, complete with pixel-perfect formatting,
161 embedded fonts, and 2D vector graphics. You can think of a PDF document as the
162 digital equivalent of a printed document; indeed, PDFs are often used in
163 distributing documents for the purpose of printing them.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
164
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
165 You can easily generate PDFs with Python and Django thanks to the excellent
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
166 open source ReportLab library (http://www.reportlab.org/rl_toolkit.html).
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
167 The advantage of generating PDF files dynamically is that you can create
168 customized PDFs for different purposes -- say, for different users or
169 different pieces of content.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
170
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
171 For example, your humble authors used Django and ReportLab at KUSports.com to
172 generate customized, printer-ready NCAA tournament brackets.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
173
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
174 Installing ReportLab
175 --------------------
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
176
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
177 Before you do any PDF generation, however, you'll need to install ReportLab.
178 It's usually simple: just download and install the library from
179 http://www.reportlab.org/downloads.html.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
180
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
181 .. note::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
182
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
183 If you're using a modern Linux distribution, you might want to check your
184 package management utility before installing ReportLab. Most
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
185 package repositories have added ReportLab.
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
186
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
187 For example, if you're using Ubuntu, a simple
188 ``apt-get install python-reportlab`` will do the trick nicely.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
189
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
190 The user guide (naturally available only as a PDF file) at
191 http://www.reportlab.org/rsrc/userguide.pdf has additional installation
192 instructions.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
193
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
194 Test your installation by importing it in the Python interactive interpreter::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
195
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
196 >>> import reportlab
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
197
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
198 If that command doesn't raise any errors, the installation worked.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
199
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
200 Writing Your View
201 -----------------
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
202
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
203 Like CSV, generating PDFs dynamically with Django is easy because the ReportLab
204 API acts on file-like objects.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
205
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
206 Here's a "Hello World" example::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
207
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
208 from reportlab.pdfgen import canvas
209 from django.http import HttpResponse
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
210
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
211 def hello_pdf(request):
212 # Create the HttpResponse object with the appropriate PDF headers.
213 response = HttpResponse(mimetype='application/pdf')
214 response['Content-Disposition'] = 'attachment; filename=hello.pdf'
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
215
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
216 # Create the PDF object, using the response object as its "file."
217 p = canvas.Canvas(response)
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
218
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
219 # Draw things on the PDF. Here's where the PDF generation happens.
220 # See the ReportLab documentation for the full list of functionality.
221 p.drawString(100, 100, "Hello world.")
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
222
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
223 # Close the PDF object cleanly, and we're done.
224 p.showPage()
225 p.save()
226 return response
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
227
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
228 .. SL Tested ok
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
229
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
230 A few notes are in order:
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
231
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
232 * Here we use the ``application/pdf`` MIME type. This tells browsers that
233 the document is a PDF file, rather than an HTML file. If you leave off
234 this information, browsers will probably interpret the response as HTML,
235 which will result in scary gobbledygook in the browser window.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
236
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
237 * Hooking into the ReportLab API is easy: just pass ``response`` as the
238 first argument to ``canvas.Canvas``. The ``Canvas`` class expects a
239 file-like object, and ``HttpResponse`` objects fit the bill.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
240
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
241 * All subsequent PDF-generation methods are called on the PDF
242 object (in this case, ``p``), not on ``response``.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
243
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
244 * Finally, it's important to call ``showPage()`` and ``save()`` on the PDF
245 file -- or else, you'll end up with a corrupted PDF file.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
246
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
247 Complex PDFs
248 ------------
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
249
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
250 If you're creating a complex PDF document (or any large data blob), consider
251 using the ``cStringIO`` library as a temporary holding place for your PDF
252 file. The ``cStringIO`` library provides a file-like object interface that is
253 written in C for maximum efficiency.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
254
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
255 Here's the previous "Hello World" example rewritten to use ``cStringIO``::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
256
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
257 from cStringIO import StringIO
258 from reportlab.pdfgen import canvas
259 from django.http import HttpResponse
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
260
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
261 def hello_pdf(request):
262 # Create the HttpResponse object with the appropriate PDF headers.
263 response = HttpResponse(mimetype='application/pdf')
264 response['Content-Disposition'] = 'attachment; filename=hello.pdf'
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
265
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
266 temp = StringIO()
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
267
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
268 # Create the PDF object, using the StringIO object as its "file."
269 p = canvas.Canvas(temp)
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
270
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
271 # Draw things on the PDF. Here's where the PDF generation happens.
272 # See the ReportLab documentation for the full list of functionality.
273 p.drawString(100, 100, "Hello world.")
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
274
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
275 # Close the PDF object cleanly.
276 p.showPage()
277 p.save()
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
278
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
279 # Get the value of the StringIO buffer and write it to the response.
280 response.write(temp.getvalue())
281 return response
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
282
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
283 .. SL Tested ok
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
284
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
285 Other Possibilities
286 ===================
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
287
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
288 There's a whole host of other types of content you can generate in Python.
289 Here are a few more ideas and some pointers to libraries you could use to
290 implement them:
291
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
292 * *ZIP files*: Python's standard library ships with the
293 ``zipfile`` module, which can both read and write compressed ZIP files.
294 You could use it to provide on-demand archives of a bunch of files, or
295 perhaps compress large documents when requested. You could similarly
296 produce TAR files using the standard library's ``tarfile`` module.
297
298 * *Dynamic images*: The Python Imaging Library
299 (PIL; http://www.pythonware.com/products/pil/) is a fantastic toolkit for
300 producing images (PNG, JPEG, GIF, and a whole lot more). You could use
301 it to automatically scale down images into thumbnails, composite
302 multiple images into a single frame, or even do Web-based image
303 processing.
304
305 * *Plots and charts*: There are a number of powerful Python plotting and
306 charting libraries you could use to produce on-demand maps, charts,
307 plots, and graphs. We can't possibly list them all, so here are
308 a couple of the highlights:
309
310 * ``matplotlib`` (http://matplotlib.sourceforge.net/) can be
311 used to produce the type of high-quality plots usually generated
312 with MatLab or Mathematica.
313
314 * ``pygraphviz`` (http://networkx.lanl.gov/pygraphviz/), an
315 interface to the Graphviz graph layout toolkit
316 (http://graphviz.org/), can be used for generating structured diagrams of
317 graphs and networks.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
318
319 In general, any Python library capable of writing to a file can be hooked into
320 Django. The possibilities are immense.
321
322 Now that we've looked at the basics of generating non-HTML content, let's step
323 up a level of abstraction. Django ships with some pretty nifty built-in tools
324 for generating some common types of non-HTML content.
325
326 The Syndication Feed Framework
327 ==============================
328
329 Django comes with a high-level syndication-feed-generating framework that
330 makes creating RSS and Atom feeds easy.
331
332 .. admonition:: What's RSS? What's Atom?
333
334 RSS and Atom are both XML-based formats you can use to provide
335 automatically updating "feeds" of your site's content. Read more about RSS
336 at http://www.whatisrss.com/, and get information on Atom at
337 http://www.atomenabled.org/.
338
339 To create any syndication feed, all you have to do is write a short Python
340 class. You can create as many feeds as you want.
341
342 The high-level feed-generating framework is a view that's hooked to ``/feeds/``
343 by convention. Django uses the remainder of the URL (everything after
344 ``/feeds/``) to determine which feed to return.
345
346 To create a feed, you'll write a ``Feed`` class and point to it in your
347 URLconf.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
348
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
349 Initialization
350 --------------
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
351
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
352 To activate syndication feeds on your Django site, add this URLconf::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
353
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
354 (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
355 {'feed_dict': feeds}
356 ),
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
357
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
358 This line tells Django to use the RSS framework to handle all URLs starting with
359 ``"feeds/"``. (You can change that ``"feeds/"`` prefix to fit your own needs.)
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
360
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
361 This URLconf line has an extra argument: ``{'feed_dict': feeds}``. Use this
362 extra argument to pass the syndication framework the feeds that should be
363 published under that URL.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
364
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
365 Specifically, ``feed_dict`` should be a dictionary that maps a feed's slug
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
366 (short URL label) to its ``Feed`` class. You can define the ``feed_dict``
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
367 in the URLconf itself. Here's a full example URLconf::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
368
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
369 from django.conf.urls.defaults import *
370 from mysite.feeds import LatestEntries, LatestEntriesByCategory
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
371
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
372 feeds = {
373 'latest': LatestEntries,
374 'categories': LatestEntriesByCategory,
375 }
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
376
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
377 urlpatterns = patterns('',
378 # ...
379 (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
380 {'feed_dict': feeds}),
381 # ...
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
382 )
383
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
384 The preceding example registers two feeds:
385
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
386 * The feed represented by ``LatestEntries`` will live at
387 ``feeds/latest/``.
388
389 * The feed represented by ``LatestEntriesByCategory`` will live at
390 ``feeds/categories/``.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
391
392 Once that's set up, you'll need to define the ``Feed`` classes themselves.
393
394 A ``Feed`` class is a simple Python class that represents a syndication feed.
395 A feed can be simple (e.g., a "site news" feed, or a basic feed displaying the
396 latest entries of a blog) or more complex (e.g., a feed displaying all the
397 blog entries in a particular category, where the category is variable).
398
399 ``Feed`` classes must subclass ``django.contrib.syndication.feeds.Feed``. They
400 can live anywhere in your code tree.
401
402 A Simple Feed
403 -------------
404
405 This simple example describes a feed of the latest five blog entries for a
406 given blog::
407
408 from django.contrib.syndication.feeds import Feed
409 from mysite.blog.models import Entry
410
411 class LatestEntries(Feed):
412 title = "My Blog"
413 link = "/archive/"
414 description = "The latest news about stuff."
415
416 def items(self):
417 return Entry.objects.order_by('-pub_date')[:5]
418
419 The important things to notice here are as follows:
420
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
421 * The class subclasses ``django.contrib.syndication.feeds.Feed``.
422
423 * ``title``, ``link``, and ``description`` correspond to the standard RSS
424 ``<title>``, ``<link>``, and ``<description>`` elements, respectively.
425
426 * ``items()`` is simply a method that returns a list of objects that
427 should be included in the feed as ``<item>`` elements. Although this
428 example returns ``Entry`` objects using Django's database API,
429 ``items()`` doesn't have to return model instances.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
430
431 There's just one more step. In an RSS feed, each ``<item>`` has a ``<title>``,
432 ``<link>``, and ``<description>``. We need to tell the framework what data to
433 put into those elements.
434
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
435 * To specify the contents of ``<title>`` and ``<description>``, create
436 Django templates called ``feeds/latest_title.html`` and
437 ``feeds/latest_description.html``, where ``latest`` is the ``slug``
438 specified in the URLconf for the given feed. Note that the ``.html``
439 extension is required.
440
441 The RSS system renders that template for each item, passing it two
442 template context variables:
443
444 * ``obj``: The current object (one of whichever objects you
445 returned in ``items()``).
446
447 * ``site``: A ``django.models.core.sites.Site`` object representing the
448 current site. This is useful for ``{{ site.domain }}`` or ``{{
449 site.name }}``.
450
451 If you don't create a template for either the title or description, the
452 framework will use the template ``"{{ obj }}"`` by default -- that is,
453 the normal string representation of the object. (For model objects, this
454 will be the ``__unicode__()`` method.
455
456 You can also change the names of these two templates by specifying
457 ``title_template`` and ``description_template`` as attributes of your
458 ``Feed`` class.
459
460 * To specify the contents of ``<link>``, you have two options. For each
461 item in ``items()``, Django first tries executing a
462 ``get_absolute_url()`` method on that object. If that method doesn't
463 exist, it tries calling a method ``item_link()`` in the ``Feed`` class,
464 passing it a single parameter, ``item``, which is the object itself.
465
466 Both ``get_absolute_url()`` and ``item_link()`` should return the item's
467 URL as a normal Python string.
468
469 * For the previous ``LatestEntries`` example, we could have very simple feed
470 templates. ``latest_title.html`` contains::
471
472 {{ obj.title }}
473
474 and ``latest_description.html`` contains::
475
476 {{ obj.description }}
477
478 It's almost *too* easy...
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
479
480 .. SL Tested ok
481
482 A More Complex Feed
483 -------------------
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
484
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
485 The framework also supports more complex feeds, via parameters.
486
487 For example, say your blog offers an RSS feed for every distinct "tag" you've
488 used to categorize your entries. It would be silly to create a separate
489 ``Feed`` class for each tag; that would violate the Don't Repeat Yourself
490 (DRY) principle and would couple data to programming logic.
491
492 Instead, the syndication framework lets you make generic
493 feeds that return items based on information in the feed's URL.
494
495 Your tag-specific feeds could use URLs like this:
496
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
497 * ``http://example.com/feeds/tags/python/``:
498 Returns recent entries tagged with "python"
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
499
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
500 * ``http://example.com/feeds/tags/cats/``:
501 Returns recent entries tagged with "cats"
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
502
503 The slug here is ``"tags"``. The syndication framework sees the extra URL
504 bits after the slug -- ``'python'`` and ``'cats'`` -- and gives you a hook
505 to tell it what those URL bits mean and how they should influence which items
506 get published in the feed.
507
508 An example makes this clear. Here's the code for these tag-specific feeds::
509
510 from django.core.exceptions import ObjectDoesNotExist
511 from mysite.blog.models import Entry, Tag
512
513 class TagFeed(Feed):
514 def get_object(self, bits):
515 # In case of "/feeds/tags/cats/dogs/mice/", or other such
516 # clutter, check that bits has only one member.
517 if len(bits) != 1:
518 raise ObjectDoesNotExist
519 return Tag.objects.get(tag=bits[0])
520
521 def title(self, obj):
522 return "My Blog: Entries tagged with %s" % obj.tag
523
524 def link(self, obj):
525 return obj.get_absolute_url()
526
527 def description(self, obj):
528 return "Entries tagged with %s" % obj.tag
529
530 def items(self, obj):
531 entries = Entry.objects.filter(tags__id__exact=obj.id)
532 return entries.order_by('-pub_date')[:30]
533
534 Here's the basic algorithm of the RSS framework, given this class and a
535 request to the URL ``/feeds/tags/python/``:
536
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
537 #. The framework gets the URL ``/feeds/tags/python/`` and notices there's an
538 extra bit of URL after the slug. It splits that remaining string by the
539 slash character (``"/"``) and calls the ``Feed`` class's
540 ``get_object()`` method, passing it the bits.
541
542 In this case, bits is ``['python']``. For a request to
543 ``/feeds/tags/python/django/``, bits would be ``['python', 'django']``.
544
545 #. ``get_object()`` is responsible for retrieving the given ``Tag`` object,
546 from the given ``bits``.
547
548 In this case, it uses the Django database API to
549 retrieve the ``Tag``. Note that ``get_object()`` should raise
550 ``django.core.exceptions.ObjectDoesNotExist`` if given invalid
551 parameters. There's no ``try``/``except`` around the
552 ``Tag.objects.get()`` call, because it's not necessary. That function
553 raises ``Tag.DoesNotExist`` on failure, and ``Tag.DoesNotExist`` is a
554 subclass of ``ObjectDoesNotExist``. Raising ``ObjectDoesNotExist`` in
555 ``get_object()`` tells Django to produce a 404 error for that request.
556
557 #. To generate the feed's ``<title>``, ``<link>``, and ``<description>``,
558 Django uses the ``title()``, ``link()``, and ``description()`` methods.
559 In the previous example, they were simple string class attributes, but
560 this example illustrates that they can be either strings *or* methods.
561 For each of ``title``, ``link``, and ``description``, Django follows
562 this algorithm:
563
564 #. It tries to call a method, passing the ``obj`` argument,
565 where ``obj`` is the object returned by ``get_object()``.
566
567 #. Failing that, it tries to call a method with no arguments.
568
569 #. Failing that, it uses the class attribute.
570
571 #. Finally, note that ``items()`` in this example also takes the ``obj``
572 argument. The algorithm for ``items`` is the same as described in the
573 previous step -- first, it tries ``items(obj)``, then ``items()``, and then
574 finally an ``items`` class attribute (which should be a list).
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
575
576 Full documentation of all the methods and attributes of the ``Feed`` classes is
577 always available from the official Django documentation
578 (http://docs.djangoproject.com/en/dev/ref/contrib/syndication/).
579
580 Specifying the Type of Feed
581 ---------------------------
582
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
583 By default, the syndication framework produces RSS 2.0. To change that,
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
584 add a ``feed_type`` attribute to your ``Feed`` class::
585
586 from django.utils.feedgenerator import Atom1Feed
587
588 class MyFeed(Feed):
589 feed_type = Atom1Feed
590
591 .. SL Tested ok
592
593 Note that you set ``feed_type`` to a class object, not an instance. Currently
594 available feed types are shown in Table 11-1.
595
596 .. table:: Table 11-1. Feed Types
597
598 =================================================== =====================
599 Feed Class Format
600 =================================================== =====================
601 ``django.utils.feedgenerator.Rss201rev2Feed`` RSS 2.01 (default)
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
602
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
603 ``django.utils.feedgenerator.RssUserland091Feed`` RSS 0.91
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
604
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
605 ``django.utils.feedgenerator.Atom1Feed`` Atom 1.0
606 =================================================== =====================
607
608 Enclosures
609 ----------
610
611 To specify enclosures (i.e., media resources associated with a feed item such as
612 MP3 podcast feeds), use the ``item_enclosure_url``, ``item_enclosure_length``,
613 and ``item_enclosure_mime_type`` hooks, for example::
614
615 from myproject.models import Song
616
617 class MyFeedWithEnclosures(Feed):
618 title = "Example feed with enclosures"
619 link = "/feeds/example-with-enclosures/"
620
621 def items(self):
622 return Song.objects.all()[:30]
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
623
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
624 def item_enclosure_url(self, item):
625 return item.song_url
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
626
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
627 def item_enclosure_length(self, item):
628 return item.song_length
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
629
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
630 item_enclosure_mime_type = "audio/mpeg"
631
632 .. SL Tested ok
633
634 This assumes, of course, that you've created a ``Song`` object with ``song_url``
635 and ``song_length`` (i.e., the size in bytes) fields.
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
636
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
637 Language
638 --------
639
640 Feeds created by the syndication framework automatically include the
641 appropriate ``<language>`` tag (RSS 2.0) or ``xml:lang`` attribute (Atom).
642 This comes directly from your ``LANGUAGE_CODE`` setting.
643
644 URLs
645 ----
646
647 The ``link`` method/attribute can return either an absolute URL (e.g.,
648 ``"/blog/"``) or a URL with the fully qualified domain and protocol (e.g.,
649 ``"http://www.example.com/blog/"``). If ``link`` doesn't return the domain,
650 the syndication framework will insert the domain of the current site,
651 according to your ``SITE_ID`` setting. (See Chapter 16 for more on ``SITE_ID``
652 and the sites framework.)
653
654 Atom feeds require a ``<link rel="self">`` that defines the feed's current
655 location. The syndication framework populates this automatically.
656
657 Publishing Atom and RSS Feeds in Tandem
658 ---------------------------------------
659
660 Some developers like to make available both Atom *and* RSS versions of their
661 feeds. That's easy to do with Django: just create a subclass of your ``feed``
662 class and set the ``feed_type`` to something different. Then update your
663 URLconf to add the extra versions. Here's a full example::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
664
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
665 from django.contrib.syndication.feeds import Feed
666 from django.utils.feedgenerator import Atom1Feed
667 from mysite.blog.models import Entry
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
668
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
669 class RssLatestEntries(Feed):
670 title = "My Blog"
671 link = "/archive/"
672 description = "The latest news about stuff."
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
673
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
674 def items(self):
675 return Entry.objects.order_by('-pub_date')[:5]
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
676
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
677 class AtomLatestEntries(RssLatestEntries):
678 feed_type = Atom1Feed
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
679
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
680 And here's the accompanying URLconf::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
681
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
682 from django.conf.urls.defaults import *
683 from myproject.feeds import RssLatestEntries, AtomLatestEntries
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
684
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
685 feeds = {
686 'rss': RssLatestEntries,
687 'atom': AtomLatestEntries,
688 }
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
689
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
690 urlpatterns = patterns('',
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
691 # ...
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
692 (r'^feeds/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
693 {'feed_dict': feeds}),
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
694 # ...
695 )
696
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
697 .. SL Tested ok
698
699 The Sitemap Framework
700 =====================
701
702 A *sitemap* is an XML file on your Web site that tells search engine indexers
703 how frequently your pages change and how "important" certain pages are in
704 relation to other pages on your site. This information helps search engines
705 index your site.
706
707 For example, here's a piece of the sitemap for Django's Web site
708 (http://www.djangoproject.com/sitemap.xml)::
709
710 <?xml version="1.0" encoding="UTF-8"?>
711 <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
712 <url>
713 <loc>http://www.djangoproject.com/documentation/</loc>
714 <changefreq>weekly</changefreq>
715 <priority>0.5</priority>
716 </url>
717 <url>
718 <loc>http://www.djangoproject.com/documentation/0_90/</loc>
719 <changefreq>never</changefreq>
720 <priority>0.1</priority>
721 </url>
722 ...
723 </urlset>
724
725 For more on sitemaps, see http://www.sitemaps.org/.
726
727 The Django sitemap framework automates the creation of this XML file by
728 letting you express this information in Python code. To create a sitemap,
729 you just need to write a ``Sitemap`` class and point to it in your URLconf.
730
731 Installation
732 ------------
733
734 To install the sitemap application, follow these steps:
735
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
736 #. Add ``'django.contrib.sitemaps'`` to your ``INSTALLED_APPS`` setting.
737
738 #. Make sure
739 ``'django.template.loaders.app_directories.load_template_source'`` is
740 in your ``TEMPLATE_LOADERS`` setting. It's in there by default, so
741 you'll need to change this only if you've changed that setting.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
742
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
743 #. Make sure you've installed the sites framework (see Chapter 16).
744
745 .. note::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
746
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
747 The sitemap application doesn't install any database tables. The only
748 reason it needs to go into ``INSTALLED_APPS`` is so the
749 ``load_template_source`` template loader can find the default templates.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
750
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
751 Initialization
752 --------------
753
754 To activate sitemap generation on your Django site, add this line to your
755 URLconf::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
756
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
757 (r'^sitemap\.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps})
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
758
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
759 This line tells Django to build a sitemap when a client accesses
760 ``/sitemap.xml``. Note that the dot character in ``sitemap.xml`` is escaped
761 with a backslash, because dots have a special meaning in regular expressions.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
762
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
763 The name of the sitemap file is not important, but the location is. Search
764 engines will only index links in your sitemap for the current URL level and
765 below. For instance, if ``sitemap.xml`` lives in your root directory, it may
766 reference any URL in your site. However, if your sitemap lives at
767 ``/content/sitemap.xml``, it may only reference URLs that begin with
768 ``/content/``.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
769
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
770 The sitemap view takes an extra, required argument: ``{'sitemaps':
771 sitemaps}``. ``sitemaps`` should be a dictionary that maps a short section
772 label (e.g., ``blog`` or ``news``) to its ``Sitemap`` class (e.g.,
773 ``BlogSitemap`` or ``NewsSitemap``). It may also map to an *instance* of a
774 ``Sitemap`` class (e.g., ``BlogSitemap(some_var)``).
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
775
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
776 Sitemap Classes
777 ---------------
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
778
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
779 A ``Sitemap`` class is a simple Python class that represents a "section" of
780 entries in your sitemap. For example, one ``Sitemap`` class could represent
781 all the entries of your weblog, while another could represent all of the
782 events in your events calendar.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
783
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
784 In the simplest case, all these sections get lumped together into one
785 ``sitemap.xml``, but it's also possible to use the framework to generate a
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
786 sitemap index that references individual sitemap files, one per section
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
787 (as described shortly).
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
788
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
789 ``Sitemap`` classes must subclass ``django.contrib.sitemaps.Sitemap``. They
790 can live anywhere in your code tree.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
791
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
792 For example, let's assume you have a blog system, with an ``Entry`` model, and
793 you want your sitemap to include all the links to your individual blog
794 entries. Here's how your ``Sitemap`` class might look::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
795
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
796 from django.contrib.sitemaps import Sitemap
797 from mysite.blog.models import Entry
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
798
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
799 class BlogSitemap(Sitemap):
800 changefreq = "never"
801 priority = 0.5
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
802
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
803 def items(self):
804 return Entry.objects.filter(is_draft=False)
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
805
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
806 def lastmod(self, obj):
807 return obj.pub_date
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
808
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
809 .. SL Tested ok
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
810
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
811 Declaring a ``Sitemap`` should look very similar to declaring a ``Feed``.
812 That's by design.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
813
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
814 Like ``Feed`` classes, ``Sitemap`` members can be either methods or
815 attributes. See the steps in the earlier "A Complex Example" section for more
816 about how this works.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
817
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
818 A ``Sitemap`` class can define the following methods/attributes:
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
819
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
820 * ``items`` (**required**): Provides list of objects. The framework
821 doesn't care what *type* of objects they are; all that matters is that
822 these objects get passed to the ``location()``, ``lastmod()``,
823 ``changefreq()``, and ``priority()`` methods.
824
825 * ``location`` (optional): Gives the absolute URL for a given object.
826 Here, "absolute URL" means a URL that doesn't include the protocol or
827 domain. Here are some examples:
828
829 * Good: ``'/foo/bar/'``
830 * Bad: ``'example.com/foo/bar/'``
831 * Bad: ``'http://example.com/foo/bar/'``
832
833 If ``location`` isn't provided, the framework will call the
834 ``get_absolute_url()`` method on each object as returned by
835 ``items()``.
836
837 * ``lastmod`` (optional): The object's "last modification" date, as a
838 Python ``datetime`` object.
839
840 * ``changefreq`` (optional): How often the object changes. Possible values
841 (as given by the Sitemaps specification) are as follows:
842
843 * ``'always'``
844 * ``'hourly'``
845 * ``'daily'``
846 * ``'weekly'``
847 * ``'monthly'``
848 * ``'yearly'``
849 * ``'never'``
850
851 * ``priority`` (optional): A suggested indexing priority between ``0.0``
852 and ``1.0``. The default priority of a page is ``0.5``; see the
853 http://sitemaps.org/ documentation for more about how ``priority`` works.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
854
855 Shortcuts
856 ---------
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
857
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
858 The sitemap framework provides a couple convenience classes for common cases. These
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
859 are described in the sections that follow.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
860
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
861 FlatPageSitemap
862 ```````````````
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
863
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
864 The ``django.contrib.sitemaps.FlatPageSitemap`` class looks at all flat pages
865 defined for the current site and creates an entry in the sitemap. These
866 entries include only the ``location`` attribute -- not ``lastmod``,
867 ``changefreq``, or ``priority``.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
868
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
869 See Chapter 16 for more about flat pages.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
870
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
871 GenericSitemap
872 ``````````````
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
873
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
874 The ``GenericSitemap`` class works with any generic views (see Chapter 11) you
875 already have.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
876
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
877 To use it, create an instance, passing in the same ``info_dict`` you pass to
878 the generic views. The only requirement is that the dictionary have a
879 ``queryset`` entry. It may also have a ``date_field`` entry that specifies a
880 date field for objects retrieved from the ``queryset``. This will be used for
881 the ``lastmod`` attribute in the generated sitemap. You may also pass
882 ``priority`` and ``changefreq`` keyword arguments to the ``GenericSitemap``
883 constructor to specify these attributes for all URLs.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
884
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
885 Here's an example of a URLconf using both ``FlatPageSitemap`` and
886 ``GenericSiteMap`` (with the hypothetical ``Entry`` object from earlier)::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
887
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
888 from django.conf.urls.defaults import *
889 from django.contrib.sitemaps import FlatPageSitemap, GenericSitemap
890 from mysite.blog.models import Entry
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
891
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
892 info_dict = {
893 'queryset': Entry.objects.all(),
894 'date_field': 'pub_date',
895 }
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
896
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
897 sitemaps = {
898 'flatpages': FlatPageSitemap,
899 'blog': GenericSitemap(info_dict, priority=0.6),
900 }
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
901
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
902 urlpatterns = patterns('',
903 # some generic view using info_dict
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
904 # ...
905
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
906 # the sitemap
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
907 (r'^sitemap\.xml$',
908 'django.contrib.sitemaps.views.sitemap',
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
909 {'sitemaps': sitemaps})
910 )
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
911
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
912 Creating a Sitemap Index
913 ------------------------
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
914
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
915 The sitemap framework also has the ability to create a sitemap index that
916 references individual sitemap files, one per each section defined in your
917 ``sitemaps`` dictionary. The only differences in usage are as follows:
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
918
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
919 * You use two views in your URLconf:
920 ``django.contrib.sitemaps.views.index`` and
921 ``django.contrib.sitemaps.views.sitemap``.
922
923 * The ``django.contrib.sitemaps.views.sitemap`` view should take a
924 ``section`` keyword argument.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
925
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
926 Here is what the relevant URLconf lines would look like for the previous example::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
927
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
928 (r'^sitemap.xml$',
929 'django.contrib.sitemaps.views.index',
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
930 {'sitemaps': sitemaps}),
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
931
932 (r'^sitemap-(?P<section>.+).xml$',
933 'django.contrib.sitemaps.views.sitemap',
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
934 {'sitemaps': sitemaps})
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
935
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
936 This will automatically generate a ``sitemap.xml`` file that references both
937 ``sitemap-flatpages.xml`` and ``sitemap-blog.xml``. The ``Sitemap`` classes
938 and the ``sitemaps`` dictionary don't change at all.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
939
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
940 Pinging Google
941 --------------
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
942
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
943 You may want to "ping" Google when your sitemap changes, to let it know to
944 reindex your site. The framework provides a function to do just that:
945 ``django.contrib.sitemaps.ping_google()``.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
946
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
947 ``ping_google()`` takes an optional argument, ``sitemap_url``, which should be
948 the absolute URL of your site's sitemap (e.g., ``'/sitemap.xml'``). If this
949 argument isn't provided, ``ping_google()`` will attempt to figure out your
950 sitemap by performing a reverse lookup on your URLconf.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
951
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
952 ``ping_google()`` raises the exception
953 ``django.contrib.sitemaps.SitemapNotFound`` if it cannot determine your
954 sitemap URL.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
955
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
956 One useful way to call ``ping_google()`` is from a model's ``save()`` method::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
957
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
958 from django.contrib.sitemaps import ping_google
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
959
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
960 class Entry(models.Model):
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
961 # ...
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
962 def save(self, *args, **kwargs):
963 super(Entry, self).save(*args, **kwargs)
964 try:
965 ping_google()
966 except Exception:
967 # Bare 'except' because we could get a variety
968 # of HTTP-related exceptions.
969 pass
970
971 A more efficient solution, however, would be to call ``ping_google()`` from a
972 ``cron`` script or some other scheduled task. The function makes an HTTP
973 request to Google's servers, so you may not want to introduce that network
974 overhead each time you call ``save()``.
975
976 Finally, if ``'django.contrib.sitemaps'`` is in your ``INSTALLED_APPS``, then
977 your ``manage.py`` will include a new command, ``ping_google``. This is useful
978 for command-line access to pinging. For example::
979
980 python manage.py ping_google /sitemap.xml
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
981
982 What's Next?
983 ============
984
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
985 Next, we'll continue to dig deeper into the built-in tools Django gives you.
986 `Chapter 14`_ looks at all the tools you need to provide user-customized
987 sites: sessions, users, and authentication.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
988
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
989 .. _Chapter 14: ../chapter14/
Something went wrong with that request. Please try again.