Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 522 lines (393 sloc) 20.116 kb
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
1 =========================
2 Chapter 11: Generic Views
3 =========================
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
4
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
5 Here again is a recurring theme of this book: at its worst, Web development is
6 boring and monotonous. So far, we've covered how Django tries to take away
7 some of that monotony at the model and template layers, but Web developers
8 also experience this boredom at the view level.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
9
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
10 Django's *generic views* were developed to ease that pain. They take certain
11 common idioms and patterns found in view development and abstract them so that
12 you can quickly write common views of data without having to write too much
13 code. In fact, nearly every view example in the preceding chapters could be
14 rewritten with the help of generic views.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
15
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
16 Chapter 8 touched briefly on how you'd go about making a view "generic." To
17 review, we can recognize certain common tasks, like displaying a list of
18 objects, and write code that displays a list of *any* object. Then the model in
19 question can be passed as an extra argument to the URLconf.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
20
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
21 Django ships with generic views to do the following:
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
22
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
23 * Perform common "simple" tasks: redirect to a different page, or
24 render a given template.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
25
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
26 * Display "list" and "detail" pages for a single object. The ``event_list``
27 and ``entry_list`` views from Chapter 8 are examples of list views. A
28 single event page is an example of what we call a "detail" view.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
29
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
30 * Present date-based objects in year/month/day archive pages,
31 associated detail, and "latest" pages. The Django Weblog's
32 (http://www.djangoproject.com/weblog/) year, month, and
33 day archives are built with these, as would be a typical
34 newspaper's archives.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
35
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
36 Taken together, these views provide easy interfaces to perform the most common
37 tasks developers encounter.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
38
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
39 Using Generic Views
40 ===================
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
41
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
42 All of these views are used by creating configuration dictionaries in
43 your URLconf files and passing those dictionaries as the third member of the
44 URLconf tuple for a given pattern. (See "Passing Extra Options to View
45 Functions" in Chapter 8 for an overview of this technique.)
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
46
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
47 For example, here's a simple URLconf you could use to present a static "about"
48 page::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
49
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
50 from django.conf.urls.defaults import *
51 from django.views.generic.simple import direct_to_template
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
52
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
53 urlpatterns = patterns('',
54 (r'^about/$', direct_to_template, {
55 'template': 'about.html'
56 })
57 )
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
58
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
59 Though this might seem a bit "magical" at first glance -- look, a view with no
60 code! --, it's actually exactly the same as the examples in Chapter 8: the
61 ``direct_to_template`` view simply grabs information from the extra-parameters
62 dictionary and uses that information when rendering the view.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
63
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
64 Because this generic view -- and all the others -- is a regular view function
65 like any other, we can reuse it inside our own views. As an example, let's
66 extend our "about" example to map URLs of the form ``/about/<whatever>/`` to
67 statically rendered ``about/<whatever>.html``. We'll do this by first modifying
68 the URLconf to point to a view function:
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
69
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
70 .. parsed-literal::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
71
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
72 from django.conf.urls.defaults import *
73 from django.views.generic.simple import direct_to_template
74 **from mysite.books.views import about_pages**
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
75
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
76 urlpatterns = patterns('',
77 (r'^about/$', direct_to_template, {
78 'template': 'about.html'
79 }),
80 **(r'^about/(\\w+)/$', about_pages),**
81 )
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
82
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
83 Next, we'll write the ``about_pages`` view::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
84
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
85 from django.http import Http404
86 from django.template import TemplateDoesNotExist
87 from django.views.generic.simple import direct_to_template
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
88
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
89 def about_pages(request, page):
90 try:
91 return direct_to_template(request, template="about/%s.html" % page)
92 except TemplateDoesNotExist:
93 raise Http404()
94
95 Here we're treating ``direct_to_template`` like any other function. Since it
96 returns an ``HttpResponse``, we can simply return it as-is. The only slightly
97 tricky business here is dealing with missing templates. We don't want a
98 nonexistent template to cause a server error, so we catch
99 ``TemplateDoesNotExist`` exceptions and return 404 errors instead.
100
101 .. admonition:: Is There a Security Vulnerability Here?
102
103 Sharp-eyed readers may have noticed a possible security hole: we're
104 constructing the template name using interpolated content from the browser
105 (``template="about/%s.html" % page``). At first glance, this looks like a
106 classic *directory traversal* vulnerability (discussed in detail in Chapter
107 20). But is it really?
108
109 Not exactly. Yes, a maliciously crafted value of ``page`` could cause
110 directory traversal, but although ``page`` *is* taken from the request URL,
111 not every value will be accepted. The key is in the URLconf: we're using
112 the regular expression ``\w+`` to match the ``page`` part of the URL, and
113 ``\w`` only accepts letters and numbers. Thus, any malicious characters
114 (such as dots and slashes) will be rejected by the URL resolver before they
115 reach the view itself.
116
117 Generic Views of Objects
118 ========================
119
120 The ``direct_to_template`` view certainly is useful, but Django's generic views
121 really shine when it comes to presenting views on your database content. Because
122 it's such a common task, Django comes with a handful of built-in generic views
123 that make generating list and detail views of objects incredibly easy.
124
125 Let's take a look at one of these generic views: the "object list" view. We'll
126 be using this ``Publisher`` object from Chapter 5::
127
128 class Publisher(models.Model):
129 name = models.CharField(max_length=30)
130 address = models.CharField(max_length=50)
131 city = models.CharField(max_length=60)
132 state_province = models.CharField(max_length=30)
133 country = models.CharField(max_length=50)
134 website = models.URLField()
135
136 def __unicode__(self):
137 return self.name
138
139 class Meta:
140 ordering = ['name']
141
142 To build a list page of all publishers, we'd use a URLconf along these lines::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
143
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
144 from django.conf.urls.defaults import *
145 from django.views.generic import list_detail
146 from mysite.books.models import Publisher
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
147
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
148 publisher_info = {
149 'queryset': Publisher.objects.all(),
150 }
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
151
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
152 urlpatterns = patterns('',
153 (r'^publishers/$', list_detail.object_list, publisher_info)
154 )
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
155
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
156 That's all the Python code we need to write. We still need to write a template,
157 however. We can explicitly tell the ``object_list`` view which template to use
158 by including a ``template_name`` key in the extra arguments dictionary:
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
159
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
160 .. parsed-literal::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
161
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
162 from django.conf.urls.defaults import *
163 from django.views.generic import list_detail
164 from mysite.books.models import Publisher
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
165
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
166 publisher_info = {
167 'queryset': Publisher.objects.all(),
168 **'template_name': 'publisher_list_page.html',**
169 }
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
170
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
171 urlpatterns = patterns('',
172 (r'^publishers/$', list_detail.object_list, publisher_info)
173 )
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
174
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
175 In the absence of ``template_name``, though, the ``object_list`` generic view
176 will infer one from the object's name. In this case, the inferred template will
177 be ``"books/publisher_list.html"`` -- the "books" part comes from the name of
178 the app that defines the model, while the "publisher" bit is just the
179 lowercased version of the model's name.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
180
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
181 This template will be rendered against a context containing a variable called
182 ``object_list`` that contains all the publisher objects. A very simple template
183 might look like the following::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
184
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
185 {% extends "base.html" %}
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
186
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
187 {% block content %}
188 <h2>Publishers</h2>
189 <ul>
190 {% for publisher in object_list %}
191 <li>{{ publisher.name }}</li>
192 {% endfor %}
193 </ul>
194 {% endblock %}
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
195
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
196 .. SL Tested ok
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
197
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
198 (Note that this assumes the existence of a ``base.html`` template, as we
199 provided in an example in Chapter 4.)
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
200
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
201 That's really all there is to it. All the cool features of generic views come
202 from changing the "info" dictionary passed to the generic view. Appendix D
203 documents all the generic views and all their options in detail; the rest of
204 this chapter will consider some of the common ways you might customize and
205 extend generic views.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
206
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
207 Extending Generic Views
208 =======================
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
209
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
210 There's no question that using generic views can speed up development
211 substantially. In most projects, however, there comes a moment when the
212 generic views no longer suffice. Indeed, one of the most common questions asked
213 by new Django developers is how to make generic views handle a wider array of
214 situations.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
215
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
216 Luckily, in nearly every one of these cases, there are ways to simply extend
217 generic views to handle a larger array of use cases. These situations usually
218 fall into a handful of patterns dealt with in the sections that follow.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
219
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
220 Making "Friendly" Template Contexts
221 -----------------------------------
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
222
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
223 You might have noticed that sample publisher list template stores all the books
224 in a variable named ``object_list``. While this works just fine, it isn't all
225 that "friendly" to template authors: they have to "just know" that they're
226 dealing with books here. A better name for that variable would be ``publisher_list``;
227 that variable's content is pretty obvious.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
228
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
229 We can change the name of that variable easily with the ``template_object_name``
230 argument:
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
231
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
232 .. parsed-literal::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
233
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
234 from django.conf.urls.defaults import *
235 from django.views.generic import list_detail
236 from mysite.books.models import Publisher
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
237
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
238 publisher_info = {
239 'queryset': Publisher.objects.all(),
240 'template_name': 'publisher_list_page.html',
241 'template_object_name': 'publisher',
242 }
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
243
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
244 urlpatterns = patterns('',
245 (r'^publishers/$', list_detail.object_list, publisher_info)
246 )
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
247
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
248 In the template, the generic view will append ``_list`` to the
249 ``template_object_name`` to create the variable name representing the list
250 of items.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
251
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
252 Providing a useful ``template_object_name`` is always a good idea. Your coworkers
253 who design templates will thank you.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
254
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
255 Adding Extra Context
256 --------------------
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
257
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
258 Sometimes, you might need to present some extra information beyond that
259 provided by the generic view. For example, think of showing a list of all the
260 other publishers on each publisher detail page. The ``object_detail`` generic
261 view provides the publisher to the context, but it seems there's no way to get
262 a list of *all* publishers in that template.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
263
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
264 But there is: all generic views take an extra optional parameter,
265 ``extra_context``. This is a dictionary of extra objects that will be added to
266 the template's context. So, to provide the list of all publishers on the
267 detail view, we'd use an info dictionary like this:
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
268
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
269 .. parsed-literal::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
270
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
271 publisher_info = {
272 'queryset': Publisher.objects.all(),
273 'template_object_name': 'publisher',
274 **'extra_context': {'book_list': Book.objects.all()}**
275 }
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
276
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
277 .. SL Tested ok
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
278
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
279 This would populate a ``{{ book_list }}`` variable in the template context.
280 This pattern can be used to pass any information down into the template for the
281 generic view. It's very handy.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
282
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
283 However, there's actually a subtle bug here -- can you spot it?
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
284
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
285 The problem has to do with when the queries in ``extra_context`` are evaluated.
286 Because this example puts ``Book.objects.all()`` in the URLconf, it will
287 be evaluated only once (when the URLconf is first loaded). Once you add or
288 remove publishers, you'll notice that the generic view doesn't reflect those
289 changes until you reload the Web server (see "Caching and QuerySets" in
290 Appendix C for more information about when ``QuerySet`` objects are cached and
291 evaluated).
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
292
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
293 .. note::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
294
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
295 This problem doesn't apply to the ``queryset`` generic view argument. Since
296 Django knows that particular QuerySet should *never* be cached, the generic
297 view takes care of clearing the cache when each view is rendered.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
298
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
299 The solution is to use a *callback* in ``extra_context`` instead of a value.
300 Any callable (i.e., a function) that's passed to ``extra_context`` will be
301 evaluated when the view is rendered (instead of only once). You could do this
302 with an explicitly defined function:
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
303
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
304 .. parsed-literal::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
305
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
306 **def get_books():**
307 **return Book.objects.all()**
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
308
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
309 publisher_info = {
310 'queryset': Publisher.objects.all(),
311 'template_object_name': 'publisher',
312 'extra_context': **{'book_list': get_books}**
313 }
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
314
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
315 Or, you could use a less obvious but shorter version that relies on the fact
316 that ``Book.objects.all`` is itself a callable:
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
317
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
318 .. parsed-literal::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
319
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
320 publisher_info = {
321 'queryset': Publisher.objects.all(),
322 'template_object_name': 'publisher',
323 'extra_context': **{'book_list': Book.objects.all}**
324 }
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
325
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
326 Notice the lack of parentheses after ``Book.objects.all``. This references
327 the function without actually calling it (which the generic view will do later).
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
328
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
329 Viewing Subsets of Objects
330 --------------------------
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
331
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
332 Now let's take a closer look at this ``queryset`` key we've been using all
333 along. Most generic views take one of these ``queryset`` arguments -- it's how the
334 view knows which set of objects to display (see "Selecting Objects" in Chapter 5
335 for an introduction to ``QuerySet`` objects, and see Appendix B for the complete
336 details).
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
337
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
338 To pick a simple example, we might want to order a list of books by
339 publication date, with the most recent first:
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
340
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
341 .. parsed-literal::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
342
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
343 book_info = {
344 'queryset': Book.objects.order_by('-publication_date'),
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
345 }
346
347 urlpatterns = patterns('',
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
348 (r'^publishers/$', list_detail.object_list, publisher_info),
349 **(r'^books/$', list_detail.object_list, book_info),**
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
350 )
351
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
352 .. SL Tested ok
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
353
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
354 That's a pretty simple example, but it illustrates the idea nicely. Of course,
355 you'll usually want to do more than just reorder objects. If you want to
356 present a list of books by a particular publisher, you can use the same
357 technique:
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
358
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
359 .. parsed-literal::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
360
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
361 **apress_books = {**
362 **'queryset': Book.objects.filter(publisher__name='Apress Publishing'),**
363 **'template_name': 'books/apress_list.html'**
364 **}**
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
365
366 urlpatterns = patterns('',
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
367 (r'^publishers/$', list_detail.object_list, publisher_info),
368 **(r'^books/apress/$', list_detail.object_list, apress_books),**
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
369 )
370
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
371 .. SL Tested ok
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
372
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
373 Notice that along with a filtered ``queryset``, we're also using a custom
374 template name. If we didn't, the generic view would use the same template as the
375 "vanilla" object list, which might not be what we want.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
376
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
377 Also notice that this isn't a very elegant way of doing publisher-specific
378 books. If we want to add another publisher page, we'd need another handful of
379 lines in the URLconf, and more than a few publishers would get unreasonable.
380 We'll deal with this problem in the next section.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
381
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
382 Complex Filtering with Wrapper Functions
383 ----------------------------------------
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
384
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
385 Another common need is to filter the objects given in a list page by some key
386 in the URL. Earlier we hard-coded the publisher's name in the URLconf, but what
387 if we wanted to write a view that displayed all the books by some arbitrary
388 publisher? The solution is to "wrap" the ``object_list`` generic view to avoid
389 writing a lot of code by hand. As usual, we'll start by writing a URLconf:
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
390
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
391 .. parsed-literal::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
392
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
393 urlpatterns = patterns('',
394 (r'^publishers/$', list_detail.object_list, publisher_info),
395 **(r'^books/(\\w+)/$', books_by_publisher),**
396 )
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
397
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
398 Next, we'll write the ``books_by_publisher`` view itself::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
399
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
400 from django.shortcuts import get_object_or_404
401 from django.views.generic import list_detail
402 from mysite.books.models import Book, Publisher
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
403
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
404 def books_by_publisher(request, name):
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
405
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
406 # Look up the publisher (and raise a 404 if it can't be found).
407 publisher = get_object_or_404(Publisher, name__iexact=name)
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
408
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
409 # Use the object_list view for the heavy lifting.
410 return list_detail.object_list(
411 request,
412 queryset = Book.objects.filter(publisher=publisher),
413 template_name = 'books/books_by_publisher.html',
414 template_object_name = 'book',
415 extra_context = {'publisher': publisher}
416 )
417
418 .. SL Tested ok
419
420 This works because there's really nothing special about generic views --
421 they're just Python functions. Like any view function, generic views expect a
422 certain set of arguments and return ``HttpResponse`` objects. Thus, it's
423 incredibly easy to wrap a small function around a generic view that does
424 additional work before (or after; see the next section) handing things off to the
425 generic view.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
426
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
427 .. note::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
428
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
429 Notice that in the preceding example we passed the current publisher being
430 displayed in the ``extra_context``. This is usually a good idea in wrappers
431 of this nature; it lets the template know which "parent" object is currently
432 being browsed.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
433
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
434 Performing Extra Work
435 ---------------------
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
436
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
437 The last common pattern we'll look at involves doing some extra work before
438 or after calling the generic view.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
439
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
440 Imagine we had a ``last_accessed`` field on our ``Author`` object that we were
441 using to keep track of the last time anybody looked at that author. The generic
442 ``object_detail`` view, of course, wouldn't know anything about this field, but
443 once again we could easily write a custom view to keep that field updated.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
444
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
445 First, we'd need to add an author detail bit in the URLconf to point to a
446 custom view:
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
447
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
448 .. parsed-literal::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
449
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
450 from mysite.books.views import author_detail
fdc4800 Jacob Kaplan-Moss Fixed a bunch of reST markup errors.
jacobian authored
451
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
452 urlpatterns = patterns('',
453 # ...
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
454 **(r'^authors/(?P<author_id>\\d+)/$', author_detail),**
455 # ...
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
456 )
457
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
458 Then we'd write our wrapper function::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
459
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
460 import datetime
461 from django.shortcuts import get_object_or_404
462 from django.views.generic import list_detail
463 from mysite.books.models import Author
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
464
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
465 def author_detail(request, author_id):
466 # Delegate to the generic view and get an HttpResponse.
467 response = list_detail.object_detail(
468 request,
469 queryset = Author.objects.all(),
470 object_id = author_id,
471 )
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
472
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
473 # Record the last accessed date. We do this *after* the call
474 # to object_detail(), not before it, so that this won't be called
475 # unless the Author actually exists. (If the author doesn't exist,
476 # object_detail() will raise Http404, and we won't reach this point.)
477 now = datetime.datetime.now()
478 Author.objects.filter(id=author_id).update(last_accessed=now)
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
479
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
480 return response
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
481
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
482 .. note::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
483
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
484 This code won't actually work unless you add a ``last_accessed`` field to
485 your ``Author`` model and create a ``books/author_detail.html`` template.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
486
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
487 .. SL Tested ok
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
488
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
489 We can use a similar idiom to alter the response returned by the generic view.
490 If we wanted to provide a downloadable plain-text version of the list of authors,
491 we could use a view like this::
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
492
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
493 def author_list_plaintext(request):
494 response = list_detail.object_list(
495 request,
496 queryset = Author.objects.all(),
497 mimetype = 'text/plain',
498 template_name = 'books/author_list.txt'
499 )
500 response["Content-Disposition"] = "attachment; filename=authors.txt"
501 return response
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
502
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
503 .. SL Tested ok
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
504
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
505 This works because the generic views return simple ``HttpResponse`` objects
506 that can be treated like dictionaries to set HTTP headers. This
507 ``Content-Disposition`` business, by the way, instructs the browser to
508 download and save the page instead of displaying it in the browser.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
509
510 What's Next?
511 ============
512
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
513 In this chapter we looked at only a couple of the generic views Django ships
514 with, but the general ideas presented here should apply pretty closely to any
515 generic view. Appendix C covers all the available views in detail, and it's
516 recommended reading if you want to get the most out of this powerful feature.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
517
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
518 This concludes the section of this book devoted to "advanced usage." In the
519 `next chapter`_, we cover deployment of Django applications.
acc918f Jacob Kaplan-Moss Initial import of djangobook from private SVN repo.
jacobian authored
520
d40cfe7 Jacob Kaplan-Moss Restored *2.0* version of the book, not 1.0!
jacobian authored
521 .. _next chapter: ../chapter12/
Something went wrong with that request. Please try again.