|
1 ============= |
|
2 Writing Views |
|
3 ============= |
|
4 |
|
5 A view function, or *view* for short, is simply a Python function that takes a |
|
6 Web request and returns a Web response. This response can be the HTML contents |
|
7 of a Web page, or a redirect, or a 404 error, or an XML document, or an image . |
|
8 . . or anything, really. The view itself contains whatever arbitrary logic is |
|
9 necessary to return that response. This code can live anywhere you want, as long |
|
10 as it's on your Python path. There's no other requirement--no "magic," so to |
|
11 speak. For the sake of putting the code *somewhere*, let's create a file called |
|
12 ``views.py`` in the ``mysite`` directory, which you created in the previous |
|
13 chapter. |
|
14 |
|
15 A simple view |
|
16 ============= |
|
17 |
|
18 Here's a view that returns the current date and time, as an HTML document: |
|
19 |
|
20 .. code-block:: python |
|
21 |
|
22 from django.http import HttpResponse |
|
23 import datetime |
|
24 |
|
25 def current_datetime(request): |
|
26 now = datetime.datetime.now() |
|
27 html = "<html><body>It is now %s.</body></html>" % now |
|
28 return HttpResponse(html) |
|
29 |
|
30 Let's step through this code one line at a time: |
|
31 |
|
32 * First, we import the class :class:`~django.http.HttpResponse` from the |
|
33 :mod:`django.http` module, along with Python's ``datetime`` library. |
|
34 |
|
35 * Next, we define a function called ``current_datetime``. This is the view |
|
36 function. Each view function takes an :class:`~django.http.HttpRequest` |
|
37 object as its first parameter, which is typically named ``request``. |
|
38 |
|
39 Note that the name of the view function doesn't matter; it doesn't have to |
|
40 be named in a certain way in order for Django to recognize it. We're |
|
41 calling it ``current_datetime`` here, because that name clearly indicates |
|
42 what it does. |
|
43 |
|
44 * The view returns an :class:`~django.http.HttpResponse` object that |
|
45 contains the generated response. Each view function is responsible for |
|
46 returning an :class:`~django.http.HttpResponse` object. (There are |
|
47 exceptions, but we'll get to those later.) |
|
48 |
|
49 .. admonition:: Django's Time Zone |
|
50 |
|
51 Django includes a ``TIME_ZONE`` setting that defaults to |
|
52 ``America/Chicago``. This probably isn't where you live, so you might want |
|
53 to change it in your settings file. |
|
54 |
|
55 Mapping URLs to Views |
|
56 ===================== |
|
57 |
|
58 So, to recap, this view function returns an HTML page that includes the current |
|
59 date and time. To display this view at a particular URL, you'll need to create a |
|
60 *URLconf*; see :doc:`/topics/http/urls` for instructions. |
|
61 |
|
62 Returning errors |
|
63 ================ |
|
64 |
|
65 Returning HTTP error codes in Django is easy. There are subclasses of |
|
66 :class:`~django.http.HttpResponse` for a number of common HTTP status codes |
|
67 other than 200 (which means *"OK"*). You can find the full list of available |
|
68 subclasses in the :ref:`request/response <ref-httpresponse-subclasses>` |
|
69 documentation. Just return an instance of one of those subclasses instead of |
|
70 a normal :class:`~django.http.HttpResponse` in order to signify an error. For |
|
71 example:: |
|
72 |
|
73 def my_view(request): |
|
74 # ... |
|
75 if foo: |
|
76 return HttpResponseNotFound('<h1>Page not found</h1>') |
|
77 else: |
|
78 return HttpResponse('<h1>Page was found</h1>') |
|
79 |
|
80 There isn't a specialized subclass for every possible HTTP response code, |
|
81 since many of them aren't going to be that common. However, as documented in |
|
82 the :class:`~django.http.HttpResponse` documentation, you can also pass the |
|
83 HTTP status code into the constructor for :class:`~django.http.HttpResponse` |
|
84 to create a return class for any status code you like. For example:: |
|
85 |
|
86 def my_view(request): |
|
87 # ... |
|
88 |
|
89 # Return a "created" (201) response code. |
|
90 return HttpResponse(status=201) |
|
91 |
|
92 Because 404 errors are by far the most common HTTP error, there's an easier way |
|
93 to handle those errors. |
|
94 |
|
95 The Http404 exception |
|
96 --------------------- |
|
97 |
|
98 .. class:: django.http.Http404() |
|
99 |
|
100 When you return an error such as :class:`~django.http.HttpResponseNotFound`, |
|
101 you're responsible for defining the HTML of the resulting error page:: |
|
102 |
|
103 return HttpResponseNotFound('<h1>Page not found</h1>') |
|
104 |
|
105 For convenience, and because it's a good idea to have a consistent 404 error page |
|
106 across your site, Django provides an ``Http404`` exception. If you raise |
|
107 ``Http404`` at any point in a view function, Django will catch it and return the |
|
108 standard error page for your application, along with an HTTP error code 404. |
|
109 |
|
110 Example usage:: |
|
111 |
|
112 from django.http import Http404 |
|
113 |
|
114 def detail(request, poll_id): |
|
115 try: |
|
116 p = Poll.objects.get(pk=poll_id) |
|
117 except Poll.DoesNotExist: |
|
118 raise Http404 |
|
119 return render_to_response('polls/detail.html', {'poll': p}) |
|
120 |
|
121 In order to use the ``Http404`` exception to its fullest, you should create a |
|
122 template that is displayed when a 404 error is raised. This template should be |
|
123 called ``404.html`` and located in the top level of your template tree. |
|
124 |
|
125 Customizing error views |
|
126 ======================= |
|
127 |
|
128 The 404 (page not found) view |
|
129 ----------------------------- |
|
130 |
|
131 When you raise an ``Http404`` exception, Django loads a special view devoted |
|
132 to handling 404 errors. By default, it's the view |
|
133 ``django.views.defaults.page_not_found``, which loads and renders the template |
|
134 ``404.html``. |
|
135 |
|
136 This means you need to define a ``404.html`` template in your root template |
|
137 directory. This template will be used for all 404 errors. |
|
138 |
|
139 This ``page_not_found`` view should suffice for 99% of Web applications, but if |
|
140 you want to override the 404 view, you can specify ``handler404`` in your |
|
141 URLconf, like so:: |
|
142 |
|
143 handler404 = 'mysite.views.my_custom_404_view' |
|
144 |
|
145 Behind the scenes, Django determines the 404 view by looking for ``handler404``. |
|
146 By default, URLconfs contain the following line:: |
|
147 |
|
148 from django.conf.urls.defaults import * |
|
149 |
|
150 That takes care of setting ``handler404`` in the current module. As you can see |
|
151 in ``django/conf/urls/defaults.py``, ``handler404`` is set to |
|
152 ``'django.views.defaults.page_not_found'`` by default. |
|
153 |
|
154 Three things to note about 404 views: |
|
155 |
|
156 * The 404 view is also called if Django doesn't find a match after checking |
|
157 every regular expression in the URLconf. |
|
158 |
|
159 * If you don't define your own 404 view -- and simply use the |
|
160 default, which is recommended -- you still have one obligation: |
|
161 you must create a ``404.html`` template in the root of your |
|
162 template directory. The default 404 view will use that template |
|
163 for all 404 errors. The default 404 view will pass one variable |
|
164 to the template: ``request_path``, which is the URL that resulted |
|
165 in the 404. |
|
166 |
|
167 * The 404 view is passed a :class:`~django.template.RequestContext` and |
|
168 will have access to variables supplied by your |
|
169 :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting (e.g., |
|
170 :setting:`MEDIA_URL`). |
|
171 |
|
172 * If :setting:`DEBUG` is set to ``True`` (in your settings module), then |
|
173 your 404 view will never be used, and the traceback will be displayed |
|
174 instead. |
|
175 |
|
176 The 500 (server error) view |
|
177 ---------------------------- |
|
178 |
|
179 Similarly, Django executes special-case behavior in the case of runtime errors |
|
180 in view code. If a view results in an exception, Django will, by default, call |
|
181 the view ``django.views.defaults.server_error``, which loads and renders the |
|
182 template ``500.html``. |
|
183 |
|
184 This means you need to define a ``500.html`` template in your root template |
|
185 directory. This template will be used for all server errors. The default 500 |
|
186 view passes no variables to this template and is rendered with an empty |
|
187 ``Context`` to lessen the chance of additional errors. |
|
188 |
|
189 This ``server_error`` view should suffice for 99% of Web applications, but if |
|
190 you want to override the view, you can specify ``handler500`` in your |
|
191 URLconf, like so:: |
|
192 |
|
193 handler500 = 'mysite.views.my_custom_error_view' |
|
194 |
|
195 Behind the scenes, Django determines the error view by looking for ``handler500``. |
|
196 By default, URLconfs contain the following line:: |
|
197 |
|
198 from django.conf.urls.defaults import * |
|
199 |
|
200 That takes care of setting ``handler500`` in the current module. As you can see |
|
201 in ``django/conf/urls/defaults.py``, ``handler500`` is set to |
|
202 ``'django.views.defaults.server_error'`` by default. |