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