2
2
Writing your first Django app, part 2
3
3
=====================================
5
By Adrian Holovaty <holovaty@gmail.com>
7
5
This tutorial begins where `Tutorial 1`_ left off. We're continuing the Web-poll
8
6
application and will focus on Django's automatically-generated admin site.
31
29
activate the admin site for your installation, do these three things:
33
31
* Add ``"django.contrib.admin"`` to your ``INSTALLED_APPS`` setting.
34
* Run the command ``python manage.py install admin``. This will create an
35
extra database table that the admin needs.
36
* Edit your ``myproject/urls.py`` file and uncomment the line below
32
* Run ``python manage.py syncdb``. Since you have added a new application
33
to ``INSTALLED_APPS``, the database tables need to be updated.
34
* Edit your ``mysite/urls.py`` file and uncomment the line below
37
35
"Uncomment this for admin:". This file is a URLconf; we'll dig into
38
36
URLconfs in the next tutorial. For now, all you need to know is that it
39
37
maps URL roots to applications.
44
Run the following command to create a superuser account for your admin site::
46
python manage.py createsuperuser
48
The script will prompt you for a username, e-mail address and password (twice).
50
39
Start the development server
51
40
============================
82
71
But where's our poll app? It's not displayed on the admin index page.
84
73
Just one thing to do: We need to specify in the ``Poll`` model that ``Poll``
85
objects have an admin interface. Edit the ``myproject/polls/models/polls.py``
86
file and make the following change to add an inner ``META`` class with an
74
objects have an admin interface. Edit the ``mysite/polls/models/polls.py``
75
file and make the following change to add an inner ``Admin`` class::
89
class Poll(meta.Model):
77
class Poll(models.Model):
94
The ``class META`` contains all `non-field metadata`_ about this model.
82
The ``class Admin`` will contain all the settings that control how this model
83
appears in the Django admin. All the settings are optional, however, so
84
creating an empty class means "give this object an admin interface using
85
all the default options."
96
87
Now reload the Django admin page to see your changes. Note that you don't have
97
to restart the development server -- it auto-reloads code.
99
.. _non-field metadata: http://www.djangoproject.com/documentation/model_api/#meta-options
88
to restart the development server -- the server will auto-reloads your project,
89
so any modifications code will be seen immediately in your browser.
101
91
Explore the free admin functionality
102
92
====================================
104
Now that ``Poll`` has the ``admin`` attribute, Django knows that it should be
94
Now that ``Poll`` has the inner ``Admin`` class, Django knows that it should be
105
95
displayed on the admin index page:
107
97
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin03t.png
125
115
Things to note here:
127
117
* The form is automatically generated from the Poll model.
128
* The different model field types (``meta.DateTimeField``, ``meta.CharField``)
118
* The different model field types (``models.DateTimeField``, ``models.CharField``)
129
119
correspond to the appropriate HTML input widget. Each type of field knows
130
120
how to display itself in the Django admin.
131
121
* Each ``DateTimeField`` gets free JavaScript shortcuts. Dates get a "Today"
157
147
Take a few minutes to marvel at all the code you didn't have to write.
159
149
Let's customize this a bit. We can reorder the fields by explicitly adding a
160
``fields`` parameter to ``meta.Admin``::
150
``fields`` parameter to ``Admin``::
164
154
(None, {'fields': ('pub_date', 'question')}),
168
157
That made the "Publication date" show up first instead of second:
176
165
And speaking of forms with dozens of fields, you might want to split the form
177
166
up into fieldsets::
181
170
(None, {'fields': ('question',)}),
182
171
('Date information', {'fields': ('pub_date',)}),
186
174
The first element of each tuple in ``fields`` is the title of the fieldset.
187
175
Here's what our form looks like now:
195
183
This is useful when you have a long form that contains a number of fields that
196
184
aren't commonly used::
200
188
(None, {'fields': ('question',)}),
201
189
('Date information', {'fields': ('pub_date',), 'classes': 'collapse'}),
205
192
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin09.png
206
193
:alt: Fieldset is initially collapsed
216
203
There are two ways to solve this problem. The first is to give the ``Choice``
217
model its own ``admin`` attribute, just as we did with ``Poll``. Here's what
204
model its own inner ``Admin`` class, just as we did with ``Poll``. Here's what
218
205
that would look like::
220
class Choice(meta.Model):
207
class Choice(models.Model):
225
212
Now "Choices" is an available option in the Django admin. The "Add choice" form
242
229
It'd be better if you could add a bunch of Choices directly when you create the
243
230
Poll object. Let's make that happen.
245
Remove the ``admin`` for the Choice model. Then, edit the ``ForeignKey(Poll)``
232
Remove the ``Admin`` for the Choice model. Then, edit the ``ForeignKey(Poll)``
248
poll = meta.ForeignKey(Poll, edit_inline=meta.STACKED, num_in_admin=3)
235
poll = models.ForeignKey(Poll, edit_inline=models.STACKED, num_in_admin=3)
250
237
This tells Django: "Choice objects are edited on the Poll admin page. By
251
238
default, provide enough fields for 3 Choices."
253
240
Then change the other fields in ``Choice`` to give them ``core=True``::
255
choice = meta.CharField(maxlength=200, core=True)
256
votes = meta.IntegerField(core=True)
242
choice = models.CharField(maxlength=200, core=True)
243
votes = models.IntegerField(core=True)
258
245
This tells Django: "When you edit a Choice on the Poll admin page, the 'choice'
259
246
and 'votes' fields are required. The presence of at least one of them signifies
277
264
fields for entering related Choice objects. For that reason, Django offers an
278
265
alternate way of displaying inline related objects::
280
poll = meta.ForeignKey(Poll, edit_inline=meta.TABULAR, num_in_admin=3)
267
poll = models.ForeignKey(Poll, edit_inline=models.TABULAR, num_in_admin=3)
282
With that ``edit_inline=meta.TABULAR`` (instead of ``meta.STACKED``), the
269
With that ``edit_inline=models.TABULAR`` (instead of ``models.STACKED``), the
283
270
related objects are displayed in a more compact, table-based format:
285
272
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin12.png
302
289
``list_display`` option, which is a tuple of field names to display, as columns,
303
290
on the change list page for the object::
305
class Poll(meta.Model):
292
class Poll(models.Model):
310
list_display = ('question', 'pub_date'),
296
list_display = ('question', 'pub_date')
313
298
Just for good measure, let's also include the ``was_published_today`` custom
314
299
method from Tutorial 1::
316
list_display = ('question', 'pub_date', 'was_published_today'),
301
list_display = ('question', 'pub_date', 'was_published_today')
318
303
Now the poll change list page looks like this:
336
321
Let's add another improvement to the Poll change list page: Filters. Add the
337
322
following line to ``Poll.admin``::
339
list_filter = ['pub_date'],
324
list_filter = ['pub_date']
341
326
That adds a "Filter" sidebar that lets people filter the change list by the
342
327
``pub_date`` field:
353
338
This is shaping up well. Let's add some search capability::
355
search_fields = ['question'],
340
search_fields = ['question']
357
342
That adds a search box at the top of the change list. When somebody enters
358
343
search terms, Django will search the ``question`` field. You can use as many
362
347
Finally, because Poll objects have dates, it'd be convenient to be able to
363
348
drill down by date. Add this line::
365
date_hierarchy = 'pub_date',
350
date_hierarchy = 'pub_date'
367
352
That adds hierarchical navigation, by date, to the top of the change list page.
368
353
At top level, it displays all available years. Then it drills down to months
383
368
is powered by Django itself, and its interfaces use Django's own template
384
369
system. (How meta!)
386
Open your settings file (``myproject/settings.py``, remember) and look at the
371
Open your settings file (``mysite/settings.py``, remember) and look at the
387
372
``TEMPLATE_DIRS`` setting. ``TEMPLATE_DIRS`` is a tuple of filesystem
388
373
directories to check when loading Django templates. It's a search path.