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