Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 950 lines (711 sloc) 39.29 kB
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
1 ==========================
2 Chapter 16: django.contrib
3 ==========================
4
5 One of the many strengths of Python is its "batteries included" philosophy: when
6 you install Python, it comes with a large standard library of packages that you
7 can start using immediately, without having to download anything else. Django
8 aims to follow this philosophy, and it includes its own standard library of
9 add-ons useful for common Web development tasks. This chapter covers that
10 collection of add-ons.
11
12 The Django Standard Library
13 ===========================
14
15 Django's standard library lives in the package ``django.contrib``. Within each
16 subpackage is a separate piece of add-on functionality. These pieces are not
17 necessarily related, but some ``django.contrib`` subpackages may require other
18 ones.
19
20 There's no hard requirement for the types of functionality in
21 ``django.contrib``. Some of the packages include models (and hence require you
22 to install their database tables into your database), but others consist solely
23 of middleware or template tags.
24
25 The single characteristic the ``django.contrib`` packages have in common is
26 this: if you were to remove the ``django.contrib`` package entirely, you could
27 still use Django's fundamental features with no problems. When the Django
28 developers add new functionality to the framework, they use this rule of thumb
29 in deciding whether the new functionality should live in ``django.contrib`` or
30 elsewhere.
31
32 ``django.contrib`` consists of these packages:
33
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
34 * ``admin``: The Django admin site. See Chapter 6.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
35
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
36 * ``admindocs``: Auto-documentation for the Django admin site. This book
37 doesn't cover this feature; check the official Django documentation.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
38
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
39 * ``auth``: Django's authentication framework. See Chapter 14.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
40
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
41 * ``comments``: A comments application. This book doesn't cover this
42 feature; check the official Django documentation.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
43
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
44 * ``contenttypes``: A framework for hooking into "types" of content, where
45 each installed Django model is a separate content type. This framework is
46 used internally by other "contrib" applications and is mostly intended for very
47 advanced Django developers. Those developers should find out more about
48 this application by reading the source code in ``django/contrib/contenttypes``.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
49
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
50 * ``csrf``: Protection against Cross-Site Request Forgery (CSRF). See
51 the later section titled "CSRF Protection."
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
52
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
53 * ``databrowse``: A Django application that lets you browse your data. This
54 book doesn't cover this feature; check the official Django documentation.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
55
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
56 * ``flatpages``: A framework for managing simple "flat" HTML content in a
57 database. See the later section titled "Flatpages."
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
58
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
59 * ``formtools``: A number of useful higher-level libraries for dealing with
60 common patterns in forms. This book doesn't cover this feature; check the
61 official Django documentation.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
62
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
63 * ``gis``: Extensions to Django that provide for GIS (Geographic
64 Information Systems) support. These, for example, allow your Django
65 models to store geographic data and perform geographic queries. This is
66 a large, complex library and isn't covered in this book. See
67 http://geodjango.org/ for documentation.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
68
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
69 * ``humanize``: A set of Django template filters useful for adding a
70 "human touch" to data. See the later section titled "Humanizing Data."
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
71
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
72 * ``localflavor``: Assorted pieces of code that are useful for particular
73 countries or cultures. For example, this includes ways to validate U.S.
74 ZIP codes or Icelandic identification numbers.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
75
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
76 * ``markup``: A set of Django template filters that implement a number of
77 common markup languages. See the later section titled "Markup Filters."
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
78
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
79 * ``redirects``: A framework for managing redirects. See the later section titled
80 "Redirects."
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
81
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
82 * ``sessions``: Django's session framework. See Chapter 14.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
83
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
84 * ``sitemaps``: A framework for generating sitemap XML files. See Chapter 13.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
85
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
86 * ``sites``: A framework that lets you operate multiple Web sites from the
87 same database and Django installation. See the next section, "Sites."
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
88
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
89 * ``syndication``: A framework for generating syndication feeds in RSS and
90 Atom. See Chapter 13.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
91
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
92 * ``webdesign``: Django add-ons that are particularly useful to Web
93 *designers* (as opposed to developers). As of this writing, this included
94 only a single template tag, ``{% lorem %}``. Check the Django
95 documentation for information.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
96
97 The rest of this chapter goes into detail a number of ``django.contrib``
98 packages that we haven't yet covered in this book.
99
100 Sites
101 =====
102
103 Django's sites system is a generic framework that lets you operate multiple
104 Web sites from the same database and Django project. This is an abstract
105 concept, and it can be tricky to understand, so we'll start with a couple of
106 scenarios where it would be useful.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
107
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
108 Scenario 1: Reusing Data on Multiple Sites
109 ------------------------------------------
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
110
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
111 As we explained in Chapter 1, the Django-powered sites LJWorld.com and
112 Lawrence.com are operated by the same news organization: the *Lawrence
113 Journal-World* newspaper in Lawrence, Kansas. LJWorld.com focuses on news, while
114 Lawrence.com focuses on local entertainment. But sometimes editors want to
115 publish an article on *both* sites.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
116
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
117 The brain-dead way of solving the problem would be to use a separate database
118 for each site and to require site producers to publish the same story twice:
119 once for LJWorld.com and again for Lawrence.com. But that's inefficient for
120 site producers, and it's redundant to store multiple copies of the same story
121 in the database.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
122
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
123 The better solution? Both sites use the same article database, and an article
124 is associated with one or more sites via a many-to-many relationship. The
125 Django sites framework provides the database table to which articles can be
126 related. It's a hook for associating data with one or more "sites."
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
127
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
128 Scenario 2: Storing Your Site Name/Domain in One Place
129 ------------------------------------------------------
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
130
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
131 LJWorld.com and Lawrence.com both have e-mail alert functionality, which lets
132 readers sign up to get notifications when news happens. It's pretty basic: a
133 reader signs up on a Web form, and he immediately gets an e-mail saying,
134 "Thanks for your subscription."
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
135
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
136 It would be inefficient and redundant to implement this signup-processing code
137 twice, so the sites use the same code behind the scenes. But the "Thank you for
138 your subscription" notice needs to be different for each site. By using ``Site``
139 objects, we can abstract the thank-you notice to use the values of the
140 current site's ``name`` (e.g., ``'LJWorld.com'``) and ``domain`` (e.g.,
141 ``'www.ljworld.com'``).
142
143 The Django sites framework provides a place for you to store the ``name`` and
144 ``domain`` for each site in your Django project, which means you can reuse
145 those values in a generic way.
146
147 How to Use the Sites Framework
148 ------------------------------
149
150 The sites framework is more a series of conventions than a framework. The
151 whole thing is based on two simple concepts:
152
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
153 * The ``Site`` model, found in ``django.contrib.sites``, has ``domain`` and
154 ``name`` fields.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
155
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
156 * The ``SITE_ID`` setting specifies the database ID of the ``Site`` object
157 associated with that particular settings file.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
158
159 How you use these two concepts is up to you, but Django uses them in a couple
160 of ways automatically via simple conventions.
161
162 To install the sites application, follow these steps:
163
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
164 1. Add ``'django.contrib.sites'`` to your ``INSTALLED_APPS``.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
165
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
166 2. Run the command ``manage.py syncdb`` to install the ``django_site``
167 table into your database. This will also create a default site object,
168 with the domain ``example.com``.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
169
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
170 3. Change the ``example.com`` site to your own domain, and add any other
171 ``Site`` objects, either through the Django admin site or via the Python
172 API. Create a ``Site`` object for each site/domain that this Django
173 project powers.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
174
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
175 4. Define the ``SITE_ID`` setting in each of your settings files. This
176 value should be the database ID of the ``Site`` object for the site
177 powered by that settings file.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
178
179 The Sites Framework's Capabilities
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
180 ----------------------------------
181
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
182 The sections that follow describe the various things you can do with the sites
183 framework.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
184
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
185 Reusing Data on Multiple Sites
186 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
187
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
188 To reuse data on multiple sites, as explained in the first scenario, just create
189 a ``ManyToManyField`` to ``Site`` in your models, for example::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
190
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
191 from django.db import models
192 from django.contrib.sites.models import Site
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 class Article(models.Model):
195 headline = models.CharField(max_length=200)
196 # ...
197 sites = models.ManyToManyField(Site)
198
199 That's the infrastructure you need to associate articles with multiple sites in
200 your database. With that in place, you can reuse the same Django view code for
201 multiple sites. Continuing the ``Article`` model example, here's what an
202 ``article_detail`` view might look like::
203
204 from django.conf import settings
205 from django.shortcuts import get_object_or_404
206 from mysite.articles.models import Article
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 def article_detail(request, article_id):
209 a = get_object_or_404(Article, id=article_id, sites__id=settings.SITE_ID)
210 # ...
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
211
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
212 This view function is reusable because it checks the article's site
213 dynamically, according to the value of the ``SITE_ID`` setting.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
214
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
215 For example, say LJWorld.com's settings file has a ``SITE_ID`` set to ``1``, and
216 Lawrence.com's settings file has a ``SITE_ID`` set to ``2``. If this view is
217 called when LJWorld.com's settings file is active, then it will limit the
218 article lookup to articles in which the list of sites includes LJWorld.com.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
219
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
220 Associating Content with a Single Site
221 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
222
223 Similarly, you can associate a model to the ``Site`` model in a many-to-one
224 relationship using ``ForeignKey``.
225
226 For example, if each article is associated with only a single site, you could
227 use a model like this::
228
229 from django.db import models
230 from django.contrib.sites.models import Site
231
232 class Article(models.Model):
233 headline = models.CharField(max_length=200)
234 # ...
235 site = models.ForeignKey(Site)
236
237 This has the same benefits as described in the last section.
238
239 Hooking Into the Current Site from Views
240 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
241
242 On a lower level, you can use the sites framework in your Django views to do
243 particular things based on the site in which the view is being called,
244 for example::
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
245
246 from django.conf import settings
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
247
248 def my_view(request):
249 if settings.SITE_ID == 3:
250 # Do something.
251 else:
252 # Do something else.
253
254 Of course, it's ugly to hard-code the site IDs like that. A slightly cleaner way
255 of accomplishing the same thing is to check the current site's domain::
256
257 from django.conf import settings
258 from django.contrib.sites.models import Site
259
260 def my_view(request):
261 current_site = Site.objects.get(id=settings.SITE_ID)
262 if current_site.domain == 'foo.com':
263 # Do something
264 else:
265 # Do something else.
266
267 The idiom of retrieving the ``Site`` object for the value of
268 ``settings.SITE_ID`` is quite common, so the ``Site`` model's manager
269 (``Site.objects``) has a ``get_current()`` method. This example is equivalent to
270 the previous one::
271
272 from django.contrib.sites.models import Site
273
274 def my_view(request):
275 current_site = Site.objects.get_current()
276 if current_site.domain == 'foo.com':
277 # Do something
278 else:
279 # Do something else.
280
281 .. note::
282
283 In this final example, you don't have to import ``django.conf.settings``.
284
285 Getting the Current Domain for Display
286 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
287
288 For a DRY (Don't Repeat Yourself) approach to storing your site's name and
289 domain name, as explained in
290 "Scenario 2: Storing Your Site Name/Domain in One Place," just reference the
291 ``name`` and ``domain`` of the current ``Site`` object. For example::
292
293 from django.contrib.sites.models import Site
294 from django.core.mail import send_mail
295
296 def register_for_newsletter(request):
297 # Check form values, etc., and subscribe the user.
298 # ...
299 current_site = Site.objects.get_current()
300 send_mail('Thanks for subscribing to %s alerts' % current_site.name,
301 'Thanks for your subscription. We appreciate it.\n\n-The %s team.' % current_site.name,
302 'editor@%s' % current_site.domain,
303 [user_email])
304 # ...
305
306 Continuing our ongoing example of LJWorld.com and Lawrence.com, on Lawrence.com
307 this e-mail has the subject line "Thanks for subscribing to lawrence.com
308 alerts." On LJWorld.com, the e-mail has the subject line "Thanks for subscribing to
309 LJWorld.com alerts." This same site-specific behavior is applied to the e-mails'
310 message body.
311
312 An even more flexible (but more heavyweight) way of doing this would be to use
313 Django's template system. Assuming Lawrence.com and LJWorld.com have different
314 template directories (``TEMPLATE_DIRS``), you could simply delegate to the
315 template system like so::
316
317 from django.core.mail import send_mail
318 from django.template import loader, Context
319
320 def register_for_newsletter(request):
321 # Check form values, etc., and subscribe the user.
322 # ...
323 subject = loader.get_template('alerts/subject.txt').render(Context({}))
324 message = loader.get_template('alerts/message.txt').render(Context({}))
325 send_mail(subject, message, 'do-not-reply@example.com', [user_email])
326 # ...
327
328 In this case, you have to create ``subject.txt`` and ``message.txt``
329 templates in both the LJWorld.com and Lawrence.com template directories.
330 As mentioned previously, that gives you more flexibility, but it's also
331 more complex.
332
333 It's a good idea to exploit the ``Site`` objects as much as possible to remove
334 unneeded complexity and redundancy.
335
336 CurrentSiteManager
337 ------------------
338
339 If ``Site`` objects play a key role in your application, consider using the
340 ``CurrentSiteManager`` in your model(s). It's a model manager (see Chapter 10)
341 that automatically filters its queries to include only objects associated with
342 the current ``Site``.
343
344 Use ``CurrentSiteManager`` by adding it to your model explicitly. For example::
345
346 from django.db import models
347 from django.contrib.sites.models import Site
348 from django.contrib.sites.managers import CurrentSiteManager
349
350 class Photo(models.Model):
351 photo = models.FileField(upload_to='/home/photos')
352 photographer_name = models.CharField(max_length=100)
353 pub_date = models.DateField()
354 site = models.ForeignKey(Site)
355 objects = models.Manager()
356 on_site = CurrentSiteManager()
357
358 With this model, ``Photo.objects.all()`` will return all ``Photo`` objects in
359 the database, but ``Photo.on_site.all()`` will return only the ``Photo``
360 objects associated with the current site, according to the ``SITE_ID`` setting.
361
362 In other words, these two statements are equivalent::
363
364 Photo.objects.filter(site=settings.SITE_ID)
365 Photo.on_site.all()
366
367 How did ``CurrentSiteManager`` know which field of ``Photo`` was the ``Site``?
368 It defaults to looking for a field called ``site``. If your model has a
369 ``ForeignKey`` or ``ManyToManyField`` called something *other* than ``site``,
370 you need to explicitly pass that as the parameter to ``CurrentSiteManager``.
371 The following model, which has a field called ``publish_on``, demonstrates
372 this::
373
374 from django.db import models
375 from django.contrib.sites.models import Site
376 from django.contrib.sites.managers import CurrentSiteManager
377
378 class Photo(models.Model):
379 photo = models.FileField(upload_to='/home/photos')
380 photographer_name = models.CharField(max_length=100)
381 pub_date = models.DateField()
382 publish_on = models.ForeignKey(Site)
383 objects = models.Manager()
384 on_site = CurrentSiteManager('publish_on')
385
386 If you attempt to use ``CurrentSiteManager`` and pass a field name that doesn't
387 exist, Django will raise a ``ValueError``.
388
389 .. note::
390
391 You'll probably want to keep a normal (non-site-specific) ``Manager`` on
392 your model, even if you use ``CurrentSiteManager``. As explained in Appendix
393 B, if you define a manager manually, then Django won't create the automatic
394 ``objects = models.Manager()`` manager for you.
395
396 Also, certain parts of Django -- namely, the Django admin site and generic
397 views -- use whichever manager is defined *first* in the model, so if you
398 want your admin site to have access to all objects (not just site-specific
399 ones), put ``objects = models.Manager()`` in your model, before you define
400 ``CurrentSiteManager``.
401
402 How Django Uses the Sites Framework
403 -----------------------------------
404
405 Although it's not required that you use the sites framework, it's encouraged,
406 because Django takes advantage of it in a few places. Even if your
407 Django installation is powering only a single site, you should take a few
408 seconds to create the site object with your ``domain`` and ``name``, and point
409 to its ID in your ``SITE_ID`` setting.
410
411 Here's how Django uses the sites framework:
412
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
413 * In the redirects framework (see the later section "Redirects"), each
414 redirect object is associated with a particular site. When Django searches
415 for a redirect, it takes into account the current ``SITE_ID``.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
416
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
417 * In the comments framework, each comment is associated with a particular
418 site. When a comment is posted, its ``site`` is set to the current
419 ``SITE_ID``, and when comments are listed via the appropriate template
420 tag, only the comments for the current site are displayed.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
421
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
422 * In the flatpages framework (see the later section "Flatpages"), each
423 flatpage is associated with a particular site. When a flatpage is created,
424 you specify its ``site``, and the flatpage middleware checks the current
425 ``SITE_ID`` in retrieving flatpages to display.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
426
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
427 * In the syndication framework (see Chapter 13), the templates for
428 ``title`` and ``description`` automatically have access to a variable
429 ``{{ site }}``, which is the ``Site`` object representing the current
430 site. Also, the hook for providing item URLs will use the
431 ``domain`` from the current ``Site`` object if you don't specify a
432 fully qualified domain.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
433
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
434 * In the authentication framework (see Chapter 14), the
435 ``django.contrib.auth.views.login`` view passes the current ``Site`` name
436 to the template as ``{{ site_name }}`` and the current ``Site`` object as
437 ``{{ site }}``.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
438
439 Flatpages
440 =========
441
442 Often you'll have a database-driven Web application up and running, but you'll
443 need to add a couple of one-off static pages, such as an About page or a
444 Privacy Policy page. It would be possible to use a standard Web server such as
445 Apache to serve these files as flat HTML files, but that introduces an extra
446 level of complexity into your application, because then you have to worry about
447 configuring Apache, you have to set up access for your team to edit those
448 files, and you can't take advantage of Django's template system to style the
449 pages.
450
451 The solution to this problem is Django's flatpages application, which lives in the
452 package ``django.contrib.flatpages``. This application lets you manage such one-off
453 pages via Django's admin site, and it lets you specify templates for them using
454 Django's template system. It uses Django models behind the scenes, which means
455 it stores the pages in a database, just like the rest of your data, and you can
456 access flatpages with the standard Django database API.
457
458 Flatpages are keyed by their URL and site. When you create a flatpage, you
459 specify which URL it's associated with, along with which site(s) it's on. (For
460 more on sites, see the "Sites" section.)
461
462 Using Flatpages
463 ---------------
464
465 To install the flatpages application, follow these steps:
466
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
467 1. Add ``'django.contrib.flatpages'`` to your ``INSTALLED_APPS``.
468 ``django.contrib.flatpages`` depends on ``django.contrib.sites``, so make
469 sure the both packages are in ``INSTALLED_APPS``.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
470
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
471 2. Add ``'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'``
472 to your ``MIDDLEWARE_CLASSES`` setting.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
473
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
474 3. Run the command ``manage.py syncdb`` to install the two required tables
475 into your database.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
476
477 The flatpages application creates two tables in your database: ``django_flatpage``
478 and ``django_flatpage_sites``. ``django_flatpage`` simply maps a URL to a title
479 and bunch of text content. ``django_flatpage_sites`` is a many-to-many table
480 that associates a flatpage with one or more sites.
481
482 The application comes with a single ``FlatPage`` model, defined in
483 ``django/contrib/flatpages/models.py``. It looks something like this::
484
485 from django.db import models
486 from django.contrib.sites.models import Site
487
488 class FlatPage(models.Model):
489 url = models.CharField(max_length=100, db_index=True)
490 title = models.CharField(max_length=200)
491 content = models.TextField(blank=True)
492 enable_comments = models.BooleanField()
493 template_name = models.CharField(max_length=70, blank=True)
494 registration_required = models.BooleanField()
495 sites = models.ManyToManyField(Site)
496
497 Let's examine these fields one at a time:
498
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
499 * ``url``: The URL at which this flatpage lives, excluding the domain
500 name but including the leading slash (e.g., ``/about/contact/``).
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
501
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
502 * ``title``: The title of the flatpage. The framework doesn't do anything
503 special with this. It's your responsibility to display it in your
504 template.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
505
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
506 * ``content``: The content of the flatpage (i.e., the HTML of the page).
507 The framework doesn't do anything special with this. It's your
508 responsibility to display it in the template.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
509
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
510 * ``enable_comments``: Whether to enable comments on this flatpage. The
511 framework doesn't do anything special with this. You can check this value
512 in your template and display a comment form if needed.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
513
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
514 * ``template_name``: The name of the template to use for rendering this
515 flatpage. This is optional; if it's not given or if this template doesn't
516 exist, the framework will fall back to the template
517 ``flatpages/default.html``.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
518
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
519 * ``registration_required``: Whether registration is required for viewing
520 this flatpage. This integrates with Django's authentication/user
521 framework, which is explained further in Chapter 14.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
522
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
523 * ``sites``: The sites that this flatpage lives on. This integrates with
524 Django's sites framework, which is explained in the "Sites" section of
525 this chapter.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
526
527 You can create flatpages through either the Django admin interface or the
528 Django database API. For more information on this, see the section
529 "Adding, Changing, and Deleting Flatpages."
530
531 Once you've created flatpages, ``FlatpageFallbackMiddleware`` does all of
532 the work. Each time any Django application raises a 404 error, this middleware
533 checks the flatpages database for the requested URL as a last resort.
534 Specifically, it checks for a flatpage with the given URL with a site ID that
535 corresponds to the ``SITE_ID`` setting.
536
537 If it finds a match, it loads the flatpage's template or
538 ``flatpages/default.html`` if the flatpage has not specified a custom template.
539 It passes that template a single context variable, ``flatpage``, which is the
540 ``FlatPage`` object. It uses ``RequestContext`` in rendering the template.
541
542 If ``FlatpageFallbackMiddleware`` doesn't find a match, the request continues
543 to be processed as usual.
544
545 .. note::
546
547 This middleware only gets activated for 404 (page not found) errors -- not
548 for 500 (server error) or other error responses. Also note that the order of
549 ``MIDDLEWARE_CLASSES`` matters. Generally, you can put
550 ``FlatpageFallbackMiddleware`` at or near the end of the list, because it's
551 a last resort.
552
553 Adding, Changing, and Deleting Flatpages
554 ----------------------------------------
555
556 You can add, change and delete flatpages in two ways:
557
558 Via the Admin Interface
559 ~~~~~~~~~~~~~~~~~~~~~~~
560
561 If you've activated the automatic Django admin interface, you should see a
562 "Flatpages" section on the admin index page. Edit flatpages as you would edit any
563 other object in the system.
564
565 Via the Python API
566 ~~~~~~~~~~~~~~~~~~
567
568 As described previously, flatpages are represented by a standard Django model that
569 lives in ``django/contrib/flatpages/models.py``. Hence, you can access flatpage
570 objects via the Django database API, for example::
571
572 >>> from django.contrib.flatpages.models import FlatPage
573 >>> from django.contrib.sites.models import Site
574 >>> fp = FlatPage.objects.create(
575 ... url='/about/',
576 ... title='About',
577 ... content='<p>About this site...</p>',
578 ... enable_comments=False,
579 ... template_name='',
580 ... registration_required=False,
581 ... )
582 >>> fp.sites.add(Site.objects.get(id=1))
583 >>> FlatPage.objects.get(url='/about/')
584 <FlatPage: /about/ -- About>
585
586 Using Flatpage Templates
587 ------------------------
588
589 By default, flatpages are rendered via the template ``flatpages/default.html``,
590 but you can override that for a particular flatpage with the ``template_name``
591 field on the ``FlatPage`` object.
592
593 Creating the ``flatpages/default.html`` template is your responsibility. In
594 your template directory, just create a ``flatpages`` directory containing a
595 ``default.html`` file.
596
597 Flatpage templates are passed a single context variable, ``flatpage``, which is
598 the flatpage object.
599
600 Here's a sample ``flatpages/default.html`` template::
601
602 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
603 "http://www.w3.org/TR/REC-html40/loose.dtd">
604 <html>
605 <head>
606 <title>{{ flatpage.title }}</title>
607 </head>
608 <body>
609 {{ flatpage.content|safe }}
610 </body>
611 </html>
612
613 Note that we've used the ``safe`` template filter to allow ``flatpage.content``
614 to include raw HTML and bypass auto-escaping.
615
616 Redirects
617 =========
618
619 Django's redirects framework lets you manage redirects easily by storing them in
620 a database and treating them as any other Django model object. For example, you
621 can use the redirects framework to tell Django, "Redirect any request to
622 ``/music/`` to ``/sections/arts/music/``." This comes in handy when you need to
623 move things around on your site; Web developers should do whatever is necessary
624 to avoid broken links.
625
626 Using the Redirects Framework
627 -----------------------------
628
629 To install the redirects application, follow these steps:
630
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
631 1. Add ``'django.contrib.redirects'`` to your ``INSTALLED_APPS``.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
632
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
633 2. Add ``'django.contrib.redirects.middleware.RedirectFallbackMiddleware'``
634 to your ``MIDDLEWARE_CLASSES`` setting.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
635
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
636 3. Run the command ``manage.py syncdb`` to install the single required
637 table into your database.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
638
639 ``manage.py syncdb`` creates a ``django_redirect`` table in your database. This
640 is a simple lookup table with ``site_id``, ``old_path``, and ``new_path`` fields.
641
642 You can create redirects through either the Django admin interface or the Django
643 database API. For more, see the section "Adding, Changing, and Deleting
644 Redirects."
645
646 Once you've created redirects, the ``RedirectFallbackMiddleware`` class does all
647 of the work. Each time any Django application raises a 404 error, this
648 middleware checks the redirects database for the requested URL as a last resort.
649 Specifically, it checks for a redirect with the given ``old_path`` with a site
650 ID that corresponds to the ``SITE_ID`` setting. (See the earlier section "Sites"
651 for more information on ``SITE_ID`` and the sites framework.) Then it follows these steps:
652
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
653 * If it finds a match, and ``new_path`` is not empty, it redirects to
654 ``new_path``.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
655
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
656 * If it finds a match, and ``new_path`` is empty, it sends a 410 ("Gone")
657 HTTP header and an empty (contentless) response.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
658
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
659 * If it doesn't find a match, the request continues to be processed as
660 usual.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
661
662 The middleware only gets activated for 404 errors -- not for 500 errors or responses of any
663 other status code.
664
665 Note that the order of ``MIDDLEWARE_CLASSES`` matters. Generally, you can put
666 ``RedirectFallbackMiddleware`` toward the end of the list, because it's a last
667 resort.
668
669 .. note::
670
671 If you're using both the redirect and flatpage fallback middleware, consider
672 which one (redirect or flatpage) you'd like checked first. We
673 suggest flatpages before redirects (thus putting
674 the flatpage middleware before the redirect middleware), but you might feel
675 differently.
676
677 Adding, Changing, and Deleting Redirects
678 ----------------------------------------
679
680 You can add, change and delete redirects in two ways:
681
682 Via the Admin Interface
683 ~~~~~~~~~~~~~~~~~~~~~~~
684
685 If you've activated the automatic Django admin interface, you should see a
686 "Redirects" section on the admin index page. Edit redirects as you would edit any
687 other object in the system.
688
689 Via the Python API
690 ~~~~~~~~~~~~~~~~~~
691
692 Redirects are represented by a standard Django model that lives in
693 ``django/contrib/redirects/models.py``. Hence, you can access redirect objects
694 via the Django database API, for example::
695
696 >>> from django.contrib.redirects.models import Redirect
697 >>> from django.contrib.sites.models import Site
698 >>> red = Redirect.objects.create(
699 ... site=Site.objects.get(id=1),
700 ... old_path='/music/',
701 ... new_path='/sections/arts/music/',
702 ... )
703 >>> Redirect.objects.get(old_path='/music/')
704 <Redirect: /music/ ---> /sections/arts/music/>
705
706 CSRF Protection
707 ===============
708
709 The ``django.contrib.csrf`` package protects against
710 Cross-Site Request Forgery (CSRF).
711
712 CSRF, also known as "session riding," is a Web site security exploit. It
713 happens when a malicious Web site tricks a user into unknowingly loading a URL
714 from a site at which that user is already authenticated, hence taking advantage
715 of the user's authenticated status. This can be a bit tricky to understand at first,
716 so we walk through two examples in this section.
717
718 A Simple CSRF Example
719 ---------------------
720
721 Suppose you're logged in to a webmail account at ``example.com``. This webmail
722 site has a Log Out button that points to the URL ``example.com/logout`` --
723 that is, the only action you need to take in order to log out is to visit the
724 page ``example.com/logout``.
725
726 A malicious site can coerce you to visit the URL ``example.com/logout`` by
727 including that URL as a hidden ``<iframe>`` on its own (malicious) page. Thus,
728 if you're logged in to the ``example.com`` webmail account and visit the
729 malicious page that has an ``<iframe>`` to ``example.com/logout``, the act of
730 visiting the malicious page will log you out from ``example.com``.
731
732 Clearly, being logged out of a webmail site against your will is not a
733 terrifying breach of security, but this same type of exploit can happen to
734 *any* site that trusts users, such as an online banking site or an e-commerce
735 site, where the exploit could be used to initiate an order or payment without
736 the user's knowledge.
737
738 A More Complex CSRF Example
739 ---------------------------
740
741 In the previous example, ``example.com`` was partially at fault because it allowed
742 a state change (i.e., logging the user out) to be requested via the HTTP
743 ``GET`` method. It's much better practice to require an HTTP ``POST`` for any
744 request that changes state on the server. But even Web sites that require
745 ``POST`` for state-changing actions are vulnerable to CSRF.
746
747 Suppose ``example.com`` has upgraded its Log Out functionality so that it's a
748 ``<form>`` button that is requested via ``POST`` to the URL
749 ``example.com/logout``. Furthermore, the logout ``<form>`` includes this
750 hidden field::
751
752 <input type="hidden" name="confirm" value="true">
753
754 This ensures that a simple ``POST`` to the URL ``example.com/logout`` won't
755 log a user out; in order for a user to log out, the user must request
756 ``example.com/logout`` via ``POST`` *and* send the ``confirm`` ``POST``
757 variable with a value of ``'true'``.
758
759 Well, despite the extra security, this arrangement can still be exploited by
760 CSRF -- the malicious page just needs to do a little more work. Attackers can
761 create an entire form targeting your site, hide it in an invisible ``<iframe>``,
762 and then use JavaScript to submit that form automatically.
763
764 Preventing CSRF
765 ---------------
766
767 How, then, can your site protect itself from this exploit? The first step is
768 to make sure all ``GET`` requests are free of side effects. That way,
769 if a malicious site includes one of your pages as an ``<iframe>``,
770 it won't have a negative effect.
771
772 That leaves ``POST`` requests. The second step is to give each ``POST``
773 ``<form>`` a hidden field whose value is secret and is generated from the
774 user's session ID. Then, when processing the form on the server side, check for
775 that secret field and raise an error if it doesn't validate.
776
777 This is exactly what Django's CSRF prevention layer does, as explained in the
778 sections that follow.
779
780 Using the CSRF Middleware
781 ~~~~~~~~~~~~~~~~~~~~~~~~~
782
783 The ``django.contrib.csrf`` package contains only one module: ``middleware.py``. This
784 module contains a Django middleware class, ``CsrfMiddleware``, which implements
785 the CSRF protection.
786
787 To activate this CSRF protection, add ``'django.contrib.csrf.middleware.CsrfMiddleware'``
788 to the ``MIDDLEWARE_CLASSES`` setting in your settings file. This middleware
789 needs to process the response *after* ``SessionMiddleware``, so
790 ``CsrfMiddleware`` must appear *before* ``SessionMiddleware`` in the list
791 (because the response middleware is processed last-to-first). Also, it must
792 process the response before the response gets compressed or otherwise mangled,
793 so ``CsrfMiddleware`` must come after ``GZipMiddleware``. Once you've added
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
794 that to your ``MIDDLEWARE_CLASSES`` setting, you're done. See the section
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
795 "Order of MIDDLEWARE_CLASSES" in Chapter 15 for more explanation.
796
797 In case you're interested, here's how ``CsrfMiddleware`` works. It does these
798 two things:
799
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
800 1. It modifies outgoing requests by adding a hidden form field to all
801 ``POST`` forms, with the name ``csrfmiddlewaretoken`` and a value that
802 is a hash of the session ID plus a secret key. The middleware does *not*
803 modify the response if there's no session ID set, so the performance
804 penalty is negligible for requests that don't use sessions.
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
805
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
806 2. On all incoming ``POST`` requests that have the session cookie set, it
807 checks that ``csrfmiddlewaretoken`` is present and correct. If it
808 isn't, the user will get a 403 ``HTTP`` error. The content of the 403
809 error page is the message "Cross Site Request Forgery detected. Request
810 aborted."
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
811
812 This ensures that only forms originating from your Web site can be used to POST
813 data back.
814
815 This middleware deliberately targets only HTTP ``POST`` requests (and the
816 corresponding POST forms). As we explained, ``GET`` requests ought never
817 to have side effects; it's your own responsibility to ensure this.
818
819 ``POST`` requests not accompanied by a session cookie are not
820 protected, but they don't *need* to be protected, because a malicious Web site
821 could make these kind of requests anyway.
822
823 To avoid altering non-HTML requests, the middleware checks the response's
824 ``Content-Type`` header before modifying it. Only pages that are served as
825 ``text/html`` or ``application/xml+xhtml`` are modified.
826
827 Limitations of the CSRF Middleware
828 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
829
830 ``CsrfMiddleware`` requires Django's session framework to work. (See Chapter 14
831 for more on sessions.) If you're using a custom session or authentication
832 framework that manually manages session cookies, this middleware will not help
833 you.
834
835 If your application creates HTML pages and forms in some unusual way (e.g., if it
836 sends fragments of HTML in JavaScript ``document.write`` statements), you
837 might bypass the filter that adds the hidden field to the form. In this case,
838 the form submission will always fail. (This happens because
839 ``CsrfMiddleware`` uses a regular expression to add the ``csrfmiddlewaretoken``
840 field to your HTML before the page is sent to the client, and the regular
841 expression sometimes cannot handle wacky HTML.) If you suspect this might be
842 happening, just view the source in your Web browser to see whether
843 ``csrfmiddlewaretoken`` was inserted into your ``<form>``.
844
845 For more CSRF information and examples, visit http://en.wikipedia.org/wiki/CSRF
846
847 Humanizing Data
848 ===============
849
850 The package ``django.contrib.humanize`` holds a set of Django template filters
851 useful for adding a "human touch" to data. To activate these filters, add
852 ``'django.contrib.humanize'`` to your ``INSTALLED_APPS``. Once you've done
853 that, use ``{% load humanize %}`` in a template, and you'll have access to the
854 filters described in the following sections.
855
856 apnumber
857 --------
858
859 For numbers 1 through 9, this filter returns the number spelled out. Otherwise,
860 it returns the numeral. This follows Associated Press style.
861
862 Examples:
863
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
864 * 1 becomes "one".
865 * 2 becomes "two".
866 * 10 becomes "10".
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
867
868 You can pass in either an integer or a string representation of an integer.
869
870 intcomma
871 --------
872
873 This filter converts an integer to a string containing commas every three digits.
874
875 Examples:
876
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
877 * 4500 becomes "4,500".
878 * 45000 becomes "45,000".
879 * 450000 becomes "450,000".
880 * 4500000 becomes "4,500,000".
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
881
882 You can pass in either an integer or a string representation of an integer.
883
884 intword
885 -------
886
887 This filter converts a large integer to a friendly text representation. It works best for
888 numbers over 1 million.
889
890 Examples:
891
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
892 * 1000000 becomes "1.0 million".
893 * 1200000 becomes "1.2 million".
894 * 1200000000 becomes "1.2 billion".
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
895
896 Values up to 1 quadrillion (1,000,000,000,000,000) are supported.
897
898 You can pass in either an integer or a string representation of an integer.
899
900 ordinal
901 -------
902
903 This filter converts an integer to its ordinal as a string.
904
905 Examples:
906
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
907 * 1 becomes "1st".
908 * 2 becomes "2nd".
909 * 3 becomes "3rd".
910 * 254 becomes "254th".
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
911
912 You can pass in either an integer or a string representation of an integer.
913
914 Markup Filters
915 ==============
916
917 The package ``django.contrib.markup`` includes a handful of Django template
918 filters, each of which implements a common markup languages:
919
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
920 * ``textile``: Implements Textile
921 (http://en.wikipedia.org/wiki/Textile_%28markup_language%29)
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
922
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
923 * ``markdown``: Implements Markdown (http://en.wikipedia.org/wiki/Markdown)
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
924
fdc4800 @jacobian Fixed a bunch of reST markup errors.
jacobian authored
925 * ``restructuredtext``: Implements ReStructured Text
926 (http://en.wikipedia.org/wiki/ReStructuredText)
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
927
928 In each case, the filter expects formatted markup as a string and returns a
929 string representing the marked-up text. For example, the ``textile`` filter converts
930 text that is marked up in Textile format to HTML::
931
932 {% load markup %}
933 {{ object.content|textile }}
934
935 To activate these filters, add ``'django.contrib.markup'`` to your
936 ``INSTALLED_APPS`` setting. Once you've done that, use ``{% load markup %}`` in
937 a template, and you'll have access to these filters. For more documentation,
938 read the source code in ``django/contrib/markup/templatetags/markup.py.``
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
939
940 What's Next?
941 ============
942
d40cfe7 @jacobian Restored *2.0* version of the book, not 1.0!
jacobian authored
943 Many of these contributed frameworks (CSRF, the auth system, etc.) do their
944 magic by providing a piece of *middleware*. Middleware is code that runs before
945 and/or after every request and can modify requests and responses at will, to
946 extend the framework. In the `next chapter`_, we'll discuss Django's built-in
947 middleware and explain how you can write your own.
acc918f @jacobian Initial import of djangobook from private SVN repo.
jacobian authored
948
40308c0 @belgianguy Removed trailing slash, rst to html
belgianguy authored
949 .. _next chapter: chapter17.html
Something went wrong with that request. Please try again.