Fixed #8234: Corrected typo in docs/cache.txt
[django.git] / docs / tutorial03.txt
blob2ac106229f14c06cd34279b2dd4ba51d782390d6
1 =====================================
2 Writing your first Django app, part 3
3 =====================================
5 This tutorial begins where `Tutorial 2`_ left off. We're continuing the Web-poll
6 application and will focus on creating the public interface -- "views."
8 .. _Tutorial 2: ../tutorial02/
10 Philosophy
11 ==========
13 A view is a "type" of Web page in your Django application that generally serves
14 a specific function and has a specific template. For example, in a weblog
15 application, you might have the following views:
17     * Blog homepage -- displays the latest few entries.
18     * Entry "detail" page -- permalink page for a single entry.
19     * Year-based archive page -- displays all months with entries in the
20       given year.
21     * Month-based archive page -- displays all days with entries in the
22       given month.
23     * Day-based archive page -- displays all entries in the given day.
24     * Comment action -- handles posting comments to a given entry.
26 In our poll application, we'll have the following four views:
28     * Poll "archive" page -- displays the latest few polls.
29     * Poll "detail" page -- displays a poll question, with no results but
30       with a form to vote.
31     * Poll "results" page -- displays results for a particular poll.
32     * Vote action -- handles voting for a particular choice in a particular
33       poll.
35 In Django, each view is represented by a simple Python function.
37 Design your URLs
38 ================
40 The first step of writing views is to design your URL structure. You do this by
41 creating a Python module, called a URLconf. URLconfs are how Django associates
42 a given URL with given Python code.
44 When a user requests a Django-powered page, the system looks at the
45 ``ROOT_URLCONF`` setting, which contains a string in Python dotted syntax.
46 Django loads that module and looks for a module-level variable called
47 ``urlpatterns``, which is a sequence of tuples in the following format::
49     (regular expression, Python callback function [, optional dictionary])
51 Django starts at the first regular expression and makes its way down the list,
52 comparing the requested URL against each regular expression until it finds one
53 that matches.
55 When it finds a match, Django calls the Python callback function, with an
56 ``HTTPRequest`` object as the first argument, any "captured" values from the
57 regular expression as keyword arguments, and, optionally, arbitrary keyword
58 arguments from the dictionary (an optional third item in the tuple).
60 For more on ``HTTPRequest`` objects, see the `request and response documentation`_.
61 For more details on URLconfs, see the `URLconf documentation`_.
63 When you ran ``python django-admin.py startproject mysite`` at the beginning of
64 Tutorial 1, it created a default URLconf in ``mysite/urls.py``. It also
65 automatically set your ``ROOT_URLCONF`` setting (in ``settings.py``) to point
66 at that file::
68     ROOT_URLCONF = 'mysite.urls'
70 Time for an example. Edit ``mysite/urls.py`` so it looks like this::
72     from django.conf.urls.defaults import *
74     urlpatterns = patterns('',
75         (r'^polls/$', 'mysite.polls.views.index'),
76         (r'^polls/(?P<poll_id>\d+)/$', 'mysite.polls.views.detail'),
77         (r'^polls/(?P<poll_id>\d+)/results/$', 'mysite.polls.views.results'),
78         (r'^polls/(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
79     )
81 This is worth a review. When somebody requests a page from your Web site --
82 say, "/polls/23/", Django will load this Python module, because it's pointed to
83 by the ``ROOT_URLCONF`` setting. It finds the variable named ``urlpatterns``
84 and traverses the regular expressions in order. When it finds a regular
85 expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the
86 associated Python package/module: ``mysite.polls.views.detail``. That
87 corresponds to the function ``detail()`` in ``mysite/polls/views.py``.
88 Finally, it calls that ``detail()`` function like so::
90     detail(request=<HttpRequest object>, poll_id='23')
92 The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parenthesis around a
93 pattern "captures" the text matched by that pattern and sends it as an argument
94 to the view function; the ``?P<poll_id>`` defines the name that will be used to
95 identify the matched pattern; and ``\d+`` is a regular expression to match a sequence of
96 digits (i.e., a number).
98 Because the URL patterns are regular expressions, there really is no limit on
99 what you can do with them. And there's no need to add URL cruft such as
100 ``.php`` -- unless you have a sick sense of humor, in which case you can do
101 something like this::
103     (r'^polls/latest\.php$', 'mysite.polls.views.index'),
105 But, don't do that. It's silly.
107 Note that these regular expressions do not search GET and POST parameters, or
108 the domain name. For example, in a request to ``http://www.example.com/myapp/``,
109 the URLconf will look for ``/myapp/``. In a request to
110 ``http://www.example.com/myapp/?page=3``, the URLconf will look for ``/myapp/``.
112 If you need help with regular expressions, see `Wikipedia's entry`_ and the
113 `Python documentation`_. Also, the O'Reilly book "Mastering Regular
114 Expressions" by Jeffrey Friedl is fantastic.
116 Finally, a performance note: these regular expressions are compiled the first
117 time the URLconf module is loaded. They're super fast.
119 .. _Wikipedia's entry: http://en.wikipedia.org/wiki/Regular_expression
120 .. _Python documentation: http://www.python.org/doc/current/lib/module-re.html
121 .. _request and response documentation: ../request_response/
122 .. _URLconf documentation: ../url_dispatch/
124 Write your first view
125 =====================
127 Well, we haven't created any views yet -- we just have the URLconf. But let's
128 make sure Django is following the URLconf properly.
130 Fire up the Django development Web server::
132     python manage.py runserver
134 Now go to "http://localhost:8000/polls/" on your domain in your Web browser.
135 You should get a pleasantly-colored error page with the following message::
137     ViewDoesNotExist at /polls/
139     Tried index in module mysite.polls.views. Error was: 'module'
140     object has no attribute 'index'
142 This error happened because you haven't written a function ``index()`` in the
143 module ``mysite/polls/views.py``.
145 Try "/polls/23/", "/polls/23/results/" and "/polls/23/vote/". The error
146 messages tell you which view Django tried (and failed to find, because you
147 haven't written any views yet).
149 Time to write the first view. Open the file ``mysite/polls/views.py``
150 and put the following Python code in it::
152     from django.http import HttpResponse
154     def index(request):
155         return HttpResponse("Hello, world. You're at the poll index.")
157 This is the simplest view possible. Go to "/polls/" in your browser, and you
158 should see your text.
160 Now add the following view. It's slightly different, because it takes an
161 argument (which, remember, is passed in from whatever was captured by the
162 regular expression in the URLconf)::
164     def detail(request, poll_id):
165         return HttpResponse("You're looking at poll %s." % poll_id)
167 Take a look in your browser, at "/polls/34/". It'll display whatever ID you
168 provide in the URL.
170 Write views that actually do something
171 ======================================
173 Each view is responsible for doing one of two things: Returning an ``HttpResponse``
174 object containing the content for the requested page, or raising an exception
175 such as ``Http404``. The rest is up to you.
177 Your view can read records from a database, or not. It can use a template
178 system such as Django's -- or a third-party Python template system -- or not.
179 It can generate a PDF file, output XML, create a ZIP file on the fly, anything
180 you want, using whatever Python libraries you want.
182 All Django wants is that ``HttpResponse``. Or an exception.
184 Because it's convenient, let's use Django's own database API, which we covered
185 in Tutorial 1. Here's one stab at the ``index()`` view, which displays the
186 latest 5 poll questions in the system, separated by commas, according to
187 publication date::
189     from mysite.polls.models import Poll
190     from django.http import HttpResponse
192     def index(request):
193         latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
194         output = ', '.join([p.question for p in latest_poll_list])
195         return HttpResponse(output)
197 There's a problem here, though: The page's design is hard-coded in the view. If
198 you want to change the way the page looks, you'll have to edit this Python code.
199 So let's use Django's template system to separate the design from Python::
201     from django.template import Context, loader
202     from mysite.polls.models import Poll
203     from django.http import HttpResponse
205     def index(request):
206         latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
207         t = loader.get_template('polls/index.html')
208         c = Context({
209             'latest_poll_list': latest_poll_list,
210         })
211         return HttpResponse(t.render(c))
213 That code loads the template called "polls/index.html" and passes it a context. The
214 context is a dictionary mapping template variable names to Python objects.
216 Reload the page. Now you'll see an error::
218     TemplateDoesNotExist at /polls/
219     polls/index.html
221 Ah. There's no template yet. First, create a directory, somewhere on your
222 filesystem, whose contents Django can access. (Django runs as whatever user
223 your server runs.) Don't put them under your document root, though. You
224 probably shouldn't make them public, just for security's sake.
226 Then edit ``TEMPLATE_DIRS`` in your ``settings.py`` to tell Django where it can
227 find templates -- just as you did in the "Customize the admin look and feel"
228 section of Tutorial 2.
230 When you've done that, create a directory ``polls`` in your template directory.
231 Within that, create a file called ``index.html``. Note that our
232 ``loader.get_template('polls/index.html')`` code from above maps to
233 "[template_directory]/polls/index.html" on the filesystem.
235 Put the following code in that template::
237     {% if latest_poll_list %}
238         <ul>
239         {% for poll in latest_poll_list %}
240             <li>{{ poll.question }}</li>
241         {% endfor %}
242         </ul>
243     {% else %}
244         <p>No polls are available.</p>
245     {% endif %}
247 Load the page in your Web browser, and you should see a bulleted-list
248 containing the "What's up" poll from Tutorial 1.
250 A shortcut: render_to_response()
251 --------------------------------
253 It's a very common idiom to load a template, fill a context and return an
254 ``HttpResponse`` object with the result of the rendered template. Django
255 provides a shortcut. Here's the full ``index()`` view, rewritten::
257     from django.shortcuts import render_to_response
258     from mysite.polls.models import Poll
260     def index(request):
261         latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
262         return render_to_response('polls/index.html', {'latest_poll_list': latest_poll_list})
264 Note that once we've done this in all these views, we no longer need to import ``loader``, ``Context`` and ``HttpResponse``.
266 The ``render_to_response()`` function takes a template name as its first
267 argument and a dictionary as its optional second argument. It returns an
268 ``HttpResponse`` object of the given template rendered with the given context.
270 Raising 404
271 ===========
273 Now, let's tackle the poll detail view -- the page that displays the question
274 for a given poll. Here's the view::
276     from django.http import Http404
277     # ...
278     def detail(request, poll_id):
279         try:
280             p = Poll.objects.get(pk=poll_id)
281         except Poll.DoesNotExist:
282             raise Http404
283         return render_to_response('polls/detail.html', {'poll': p})
285 The new concept here: The view raises the ``django.http.Http404``
286 exception if a poll with the requested ID doesn't exist.
288 A shortcut: get_object_or_404()
289 -------------------------------
291 It's a very common idiom to use ``get()`` and raise ``Http404`` if the
292 object doesn't exist. Django provides a shortcut. Here's the ``detail()`` view,
293 rewritten::
295     from django.shortcuts import render_to_response, get_object_or_404
296     # ...
297     def detail(request, poll_id):
298         p = get_object_or_404(Poll, pk=poll_id)
299         return render_to_response('polls/detail.html', {'poll': p})
301 The ``get_object_or_404()`` function takes a Django model module as its first
302 argument and an arbitrary number of keyword arguments, which it passes to the
303 module's ``get()`` function. It raises ``Http404`` if the object doesn't
304 exist.
306 .. admonition:: Philosophy
308     Why do we use a helper function ``get_object_or_404()`` instead of
309     automatically catching the ``DoesNotExist`` exceptions at a higher level,
310     or having the model API raise ``Http404`` instead of ``DoesNotExist``?
312     Because that would couple the model layer to the view layer. One of the
313     foremost design goals of Django is to maintain loose coupling.
315 There's also a ``get_list_or_404()`` function, which works just as
316 ``get_object_or_404()`` -- except using ``filter()`` instead of
317 ``get()``. It raises ``Http404`` if the list is empty.
319 Write a 404 (page not found) view
320 =================================
322 When you raise ``Http404`` from within a view, Django will load a special view
323 devoted to handling 404 errors. It finds it by looking for the variable
324 ``handler404``, which is a string in Python dotted syntax -- the same format
325 the normal URLconf callbacks use. A 404 view itself has nothing special: It's
326 just a normal view.
328 You normally won't have to bother with writing 404 views. By default, URLconfs
329 have the following line up top::
331     from django.conf.urls.defaults import *
333 That takes care of setting ``handler404`` in the current module. As you can see
334 in ``django/conf/urls/defaults.py``, ``handler404`` is set to
335 ``'django.views.defaults.page_not_found'`` by default.
337 Three more things to note about 404 views:
339     * The 404 view is also called if Django doesn't find a match after checking
340       every regular expression in the URLconf.
341     * If you don't define your own 404 view -- and simply use the default,
342       which is recommended -- you still have one obligation: To create a
343       ``404.html`` template in the root of your template directory. The default
344       404 view will use that template for all 404 errors.
345     * If ``DEBUG`` is set to ``True`` (in your settings module) then your 404
346       view will never be used, and the traceback will be displayed instead.
348 Write a 500 (server error) view
349 ===============================
351 Similarly, URLconfs may define a ``handler500``, which points to a view to call
352 in case of server errors. Server errors happen when you have runtime errors in
353 view code.
355 Use the template system
356 =======================
358 Back to the ``detail()`` view for our poll application. Given the context 
359 variable ``poll``, here's what the "polls/detail.html" template might look
360 like::
362     <h1>{{ poll.question }}</h1>
363     <ul>
364     {% for choice in poll.choice_set.all %}
365         <li>{{ choice.choice }}</li>
366     {% endfor %}
367     </ul>
369 The template system uses dot-lookup syntax to access variable attributes. In
370 the example of ``{{ poll.question }}``, first Django does a dictionary lookup
371 on the object ``poll``. Failing that, it tries attribute lookup -- which works,
372 in this case. If attribute lookup had failed, it would've tried calling the
373 method ``question()`` on the poll object.
375 Method-calling happens in the ``{% for %}`` loop: ``poll.choice_set.all`` is
376 interpreted as the Python code ``poll.choice_set.all()``, which returns an
377 iterable of Choice objects and is suitable for use in the ``{% for %}`` tag.
379 See the `template guide`_ for full details on how templates work.
381 .. _template guide: ../templates/
383 Simplifying the URLconfs
384 ========================
386 Take some time to play around with the views and template system. As you edit
387 the URLconf, you may notice there's a fair bit of redundancy in it::
389     urlpatterns = patterns('',
390         (r'^polls/$', 'mysite.polls.views.index'),
391         (r'^polls/(?P<poll_id>\d+)/$', 'mysite.polls.views.detail'),
392         (r'^polls/(?P<poll_id>\d+)/results/$', 'mysite.polls.views.results'),
393         (r'^polls/(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
394     )
396 Namely, ``mysite.polls.views`` is in every callback.
398 Because this is a common case, the URLconf framework provides a shortcut for
399 common prefixes. You can factor out the common prefixes and add them as the
400 first argument to ``patterns()``, like so::
402     urlpatterns = patterns('mysite.polls.views',
403         (r'^polls/$', 'index'),
404         (r'^polls/(?P<poll_id>\d+)/$', 'detail'),
405         (r'^polls/(?P<poll_id>\d+)/results/$', 'results'),
406         (r'^polls/(?P<poll_id>\d+)/vote/$', 'vote'),
407     )
409 This is functionally identical to the previous formatting. It's just a bit
410 tidier.
412 Decoupling the URLconfs
413 =======================
415 While we're at it, we should take the time to decouple our poll-app URLs from
416 our Django project configuration. Django apps are meant to be pluggable -- that
417 is, each particular app should be transferrable to another Django installation
418 with minimal fuss.
420 Our poll app is pretty decoupled at this point, thanks to the strict directory
421 structure that ``python manage.py startapp`` created, but one part of it is
422 coupled to the Django settings: The URLconf.
424 We've been editing the URLs in ``mysite/urls.py``, but the URL design of an
425 app is specific to the app, not to the Django installation -- so let's move the
426 URLs within the app directory.
428 Copy the file ``mysite/urls.py`` to ``mysite/polls/urls.py``. Then,
429 change ``mysite/urls.py`` to remove the poll-specific URLs and insert an
430 ``include()``::
432     (r'^polls/', include('mysite.polls.urls')),
434 ``include()``, simply, references another URLconf. Note that the regular
435 expression doesn't have a ``$`` (end-of-string match character) but has the
436 trailing slash. Whenever Django encounters ``include()``, it chops off whatever
437 part of the URL matched up to that point and sends the remaining string to the
438 included URLconf for further processing.
440 Here's what happens if a user goes to "/polls/34/" in this system:
442 * Django will find the match at ``'^polls/'``
443 * It will strip off the matching text (``"polls/"``) and send the remaining
444   text -- ``"34/"`` -- to the 'mysite.polls.urls' URLconf for
445   further processing.
447 Now that we've decoupled that, we need to decouple the
448 'mysite.polls.urls' URLconf by removing the leading "polls/" from each
449 line::
451     urlpatterns = patterns('mysite.polls.views',
452         (r'^$', 'index'),
453         (r'^(?P<poll_id>\d+)/$', 'detail'),
454         (r'^(?P<poll_id>\d+)/results/$', 'results'),
455         (r'^(?P<poll_id>\d+)/vote/$', 'vote'),
456     )
458 The idea behind ``include()`` and URLconf decoupling is to make it easy to
459 plug-and-play URLs. Now that polls are in their own URLconf, they can be placed
460 under "/polls/", or under "/fun_polls/", or under "/content/polls/", or any
461 other URL root, and the app will still work.
463 All the poll app cares about is its relative URLs, not its absolute URLs.
465 When you're comfortable with writing views, read `part 4 of this tutorial`_ to
466 learn about simple form processing and generic views.
468 .. _part 4 of this tutorial: ../tutorial04/