mirror of
https://github.com/django/django.git
synced 2025-07-05 10:19:20 +00:00
magic-removal: updated tutorials 2 and 4 to be magic-removal-complient (refs #1464). Thanks to ChaosKCW and jbowtie.
git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
537f01c162
commit
924d9e2f6a
@ -83,25 +83,25 @@ But where's our poll app? It's not displayed on the admin index page.
|
|||||||
|
|
||||||
Just one thing to do: We need to specify in the ``Poll`` model that ``Poll``
|
Just one thing to do: We need to specify in the ``Poll`` model that ``Poll``
|
||||||
objects have an admin interface. Edit the ``myproject/polls/models/polls.py``
|
objects have an admin interface. Edit the ``myproject/polls/models/polls.py``
|
||||||
file and make the following change to add an inner ``Meta`` class with an
|
file and make the following change to add an inner ``Admin`` class::
|
||||||
``admin`` attribute::
|
|
||||||
|
|
||||||
class Poll(meta.Model):
|
class Poll(models.Model):
|
||||||
# ...
|
# ...
|
||||||
class Meta:
|
class Admin:
|
||||||
admin = meta.Admin()
|
pass
|
||||||
|
|
||||||
The ``class Meta`` contains all `non-field metadata`_ about this model.
|
The ``class Admin`` will contain all the settings that control how this model
|
||||||
|
appears in the Django admin. All the settings are optional, however, so
|
||||||
|
creating an empty class means "give this object an admin interface using
|
||||||
|
all the default options."
|
||||||
|
|
||||||
Now reload the Django admin page to see your changes. Note that you don't have
|
Now reload the Django admin page to see your changes. Note that you don't have
|
||||||
to restart the development server -- it auto-reloads code.
|
to restart the development server -- it auto-reloads code.
|
||||||
|
|
||||||
.. _non-field metadata: http://www.djangoproject.com/documentation/model_api/#meta-options
|
|
||||||
|
|
||||||
Explore the free admin functionality
|
Explore the free admin functionality
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
Now that ``Poll`` has the ``admin`` attribute, Django knows that it should be
|
Now that ``Poll`` has the inner ``Admin`` class, Django knows that it should be
|
||||||
displayed on the admin index page:
|
displayed on the admin index page:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin03t.png
|
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin03t.png
|
||||||
@ -125,7 +125,7 @@ Click the "What's up?" poll to edit it:
|
|||||||
Things to note here:
|
Things to note here:
|
||||||
|
|
||||||
* The form is automatically generated from the Poll model.
|
* The form is automatically generated from the Poll model.
|
||||||
* The different model field types (``meta.DateTimeField``, ``meta.CharField``)
|
* The different model field types (``models.DateTimeField``, ``models.CharField``)
|
||||||
correspond to the appropriate HTML input widget. Each type of field knows
|
correspond to the appropriate HTML input widget. Each type of field knows
|
||||||
how to display itself in the Django admin.
|
how to display itself in the Django admin.
|
||||||
* Each ``DateTimeField`` gets free JavaScript shortcuts. Dates get a "Today"
|
* Each ``DateTimeField`` gets free JavaScript shortcuts. Dates get a "Today"
|
||||||
@ -157,13 +157,12 @@ Customize the admin form
|
|||||||
Take a few minutes to marvel at all the code you didn't have to write.
|
Take a few minutes to marvel at all the code you didn't have to write.
|
||||||
|
|
||||||
Let's customize this a bit. We can reorder the fields by explicitly adding a
|
Let's customize this a bit. We can reorder the fields by explicitly adding a
|
||||||
``fields`` parameter to ``meta.Admin``::
|
``fields`` parameter to ``Admin``::
|
||||||
|
|
||||||
admin = meta.Admin(
|
class Admin:
|
||||||
fields = (
|
fields = (
|
||||||
(None, {'fields': ('pub_date', 'question')}),
|
(None, {'fields': ('pub_date', 'question')}),
|
||||||
),
|
)
|
||||||
)
|
|
||||||
|
|
||||||
That made the "Publication date" show up first instead of second:
|
That made the "Publication date" show up first instead of second:
|
||||||
|
|
||||||
@ -176,12 +175,11 @@ of fields, choosing an intuitive order is an important usability detail.
|
|||||||
And speaking of forms with dozens of fields, you might want to split the form
|
And speaking of forms with dozens of fields, you might want to split the form
|
||||||
up into fieldsets::
|
up into fieldsets::
|
||||||
|
|
||||||
admin = meta.Admin(
|
class Admin:
|
||||||
fields = (
|
fields = (
|
||||||
(None, {'fields': ('question',)}),
|
(None, {'fields': ('question',)}),
|
||||||
('Date information', {'fields': ('pub_date',)}),
|
('Date information', {'fields': ('pub_date',)}),
|
||||||
),
|
)
|
||||||
)
|
|
||||||
|
|
||||||
The first element of each tuple in ``fields`` is the title of the fieldset.
|
The first element of each tuple in ``fields`` is the title of the fieldset.
|
||||||
Here's what our form looks like now:
|
Here's what our form looks like now:
|
||||||
@ -195,12 +193,11 @@ You can assign arbitrary HTML classes to each fieldset. Django provides a
|
|||||||
This is useful when you have a long form that contains a number of fields that
|
This is useful when you have a long form that contains a number of fields that
|
||||||
aren't commonly used::
|
aren't commonly used::
|
||||||
|
|
||||||
admin = meta.Admin(
|
class Admin:
|
||||||
fields = (
|
fields = (
|
||||||
(None, {'fields': ('question',)}),
|
(None, {'fields': ('question',)}),
|
||||||
('Date information', {'fields': ('pub_date',), 'classes': 'collapse'}),
|
('Date information', {'fields': ('pub_date',), 'classes': 'collapse'}),
|
||||||
),
|
)
|
||||||
)
|
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin09.png
|
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin09.png
|
||||||
:alt: Fieldset is initially collapsed
|
:alt: Fieldset is initially collapsed
|
||||||
@ -214,13 +211,13 @@ the admin page doesn't display choices.
|
|||||||
Yet.
|
Yet.
|
||||||
|
|
||||||
There are two ways to solve this problem. The first is to give the ``Choice``
|
There are two ways to solve this problem. The first is to give the ``Choice``
|
||||||
model its own ``admin`` attribute, just as we did with ``Poll``. Here's what
|
model its own inner ``Admin`` class, just as we did with ``Poll``. Here's what
|
||||||
that would look like::
|
that would look like::
|
||||||
|
|
||||||
class Choice(meta.Model):
|
class Choice(models.Model):
|
||||||
# ...
|
# ...
|
||||||
class Meta:
|
class Admin:
|
||||||
admin = meta.Admin()
|
pass
|
||||||
|
|
||||||
Now "Choices" is an available option in the Django admin. The "Add choice" form
|
Now "Choices" is an available option in the Django admin. The "Add choice" form
|
||||||
looks like this:
|
looks like this:
|
||||||
@ -242,18 +239,18 @@ But, really, this is an inefficient way of adding Choice objects to the system.
|
|||||||
It'd be better if you could add a bunch of Choices directly when you create the
|
It'd be better if you could add a bunch of Choices directly when you create the
|
||||||
Poll object. Let's make that happen.
|
Poll object. Let's make that happen.
|
||||||
|
|
||||||
Remove the ``admin`` for the Choice model. Then, edit the ``ForeignKey(Poll)``
|
Remove the ``Admin`` for the Choice model. Then, edit the ``ForeignKey(Poll)``
|
||||||
field like so::
|
field like so::
|
||||||
|
|
||||||
poll = meta.ForeignKey(Poll, edit_inline=meta.STACKED, num_in_admin=3)
|
poll = models.ForeignKey(Poll, edit_inline=models.STACKED, num_in_admin=3)
|
||||||
|
|
||||||
This tells Django: "Choice objects are edited on the Poll admin page. By
|
This tells Django: "Choice objects are edited on the Poll admin page. By
|
||||||
default, provide enough fields for 3 Choices."
|
default, provide enough fields for 3 Choices."
|
||||||
|
|
||||||
Then change the other fields in ``Choice`` to give them ``core=True``::
|
Then change the other fields in ``Choice`` to give them ``core=True``::
|
||||||
|
|
||||||
choice = meta.CharField(maxlength=200, core=True)
|
choice = models.CharField(maxlength=200, core=True)
|
||||||
votes = meta.IntegerField(core=True)
|
votes = models.IntegerField(core=True)
|
||||||
|
|
||||||
This tells Django: "When you edit a Choice on the Poll admin page, the 'choice'
|
This tells Django: "When you edit a Choice on the Poll admin page, the 'choice'
|
||||||
and 'votes' fields are required. The presence of at least one of them signifies
|
and 'votes' fields are required. The presence of at least one of them signifies
|
||||||
@ -277,9 +274,9 @@ One small problem, though. It takes a lot of screen space to display all the
|
|||||||
fields for entering related Choice objects. For that reason, Django offers an
|
fields for entering related Choice objects. For that reason, Django offers an
|
||||||
alternate way of displaying inline related objects::
|
alternate way of displaying inline related objects::
|
||||||
|
|
||||||
poll = meta.ForeignKey(Poll, edit_inline=meta.TABULAR, num_in_admin=3)
|
poll = models.ForeignKey(Poll, edit_inline=models.TABULAR, num_in_admin=3)
|
||||||
|
|
||||||
With that ``edit_inline=meta.TABULAR`` (instead of ``meta.STACKED``), the
|
With that ``edit_inline=models.TABULAR`` (instead of ``models.STACKED``), the
|
||||||
related objects are displayed in a more compact, table-based format:
|
related objects are displayed in a more compact, table-based format:
|
||||||
|
|
||||||
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin12.png
|
.. image:: http://media.djangoproject.com/img/doc/tutorial/admin12.png
|
||||||
@ -302,18 +299,16 @@ helpful if we could display individual fields. To do that, use the
|
|||||||
``list_display`` option, which is a tuple of field names to display, as columns,
|
``list_display`` option, which is a tuple of field names to display, as columns,
|
||||||
on the change list page for the object::
|
on the change list page for the object::
|
||||||
|
|
||||||
class Poll(meta.Model):
|
class Poll(models.Model):
|
||||||
# ...
|
# ...
|
||||||
class Meta:
|
class Admin:
|
||||||
admin = meta.Admin(
|
# ...
|
||||||
# ...
|
list_display = ('question', 'pub_date')
|
||||||
list_display = ('question', 'pub_date'),
|
|
||||||
)
|
|
||||||
|
|
||||||
Just for good measure, let's also include the ``was_published_today`` custom
|
Just for good measure, let's also include the ``was_published_today`` custom
|
||||||
method from Tutorial 1::
|
method from Tutorial 1::
|
||||||
|
|
||||||
list_display = ('question', 'pub_date', 'was_published_today'),
|
list_display = ('question', 'pub_date', 'was_published_today')
|
||||||
|
|
||||||
Now the poll change list page looks like this:
|
Now the poll change list page looks like this:
|
||||||
|
|
||||||
@ -336,7 +331,7 @@ method a ``short_description`` attribute::
|
|||||||
Let's add another improvement to the Poll change list page: Filters. Add the
|
Let's add another improvement to the Poll change list page: Filters. Add the
|
||||||
following line to ``Poll.admin``::
|
following line to ``Poll.admin``::
|
||||||
|
|
||||||
list_filter = ['pub_date'],
|
list_filter = ['pub_date']
|
||||||
|
|
||||||
That adds a "Filter" sidebar that lets people filter the change list by the
|
That adds a "Filter" sidebar that lets people filter the change list by the
|
||||||
``pub_date`` field:
|
``pub_date`` field:
|
||||||
@ -352,7 +347,7 @@ filter options for DateTimeFields: "Any date," "Today," "Past 7 days,"
|
|||||||
|
|
||||||
This is shaping up well. Let's add some search capability::
|
This is shaping up well. Let's add some search capability::
|
||||||
|
|
||||||
search_fields = ['question'],
|
search_fields = ['question']
|
||||||
|
|
||||||
That adds a search box at the top of the change list. When somebody enters
|
That adds a search box at the top of the change list. When somebody enters
|
||||||
search terms, Django will search the ``question`` field. You can use as many
|
search terms, Django will search the ``question`` field. You can use as many
|
||||||
@ -362,7 +357,7 @@ scenes, keep it reasonable, to keep your database happy.
|
|||||||
Finally, because Poll objects have dates, it'd be convenient to be able to
|
Finally, because Poll objects have dates, it'd be convenient to be able to
|
||||||
drill down by date. Add this line::
|
drill down by date. Add this line::
|
||||||
|
|
||||||
date_hierarchy = 'pub_date',
|
date_hierarchy = 'pub_date'
|
||||||
|
|
||||||
That adds hierarchical navigation, by date, to the top of the change list page.
|
That adds hierarchical navigation, by date, to the top of the change list page.
|
||||||
At top level, it displays all available years. Then it drills down to months
|
At top level, it displays all available years. Then it drills down to months
|
||||||
|
@ -49,13 +49,13 @@ included this line::
|
|||||||
So let's create a ``vote()`` function in ``myproject/polls/views.py``::
|
So let's create a ``vote()`` function in ``myproject/polls/views.py``::
|
||||||
|
|
||||||
from django.shortcuts import get_object_or_404, render_to_response
|
from django.shortcuts import get_object_or_404, render_to_response
|
||||||
from django.models.polls import choices, polls
|
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
|
from myproject.polls.models import Choice, Poll
|
||||||
|
|
||||||
def vote(request, poll_id):
|
def vote(request, poll_id):
|
||||||
p = get_object_or_404(polls, pk=poll_id)
|
p = get_object_or_404(Poll, pk=poll_id)
|
||||||
try:
|
try:
|
||||||
selected_choice = p.get_choice(pk=request.POST['choice'])
|
selected_choice = p.choice_set.filter(pk=request.POST['choice'])
|
||||||
except (KeyError, choices.ChoiceDoesNotExist):
|
except (KeyError, choices.ChoiceDoesNotExist):
|
||||||
# Redisplay the poll voting form.
|
# Redisplay the poll voting form.
|
||||||
return render_to_response('polls/detail', {
|
return render_to_response('polls/detail', {
|
||||||
@ -102,7 +102,7 @@ After somebody votes in a poll, the ``vote()`` view redirects to the results
|
|||||||
page for the poll. Let's write that view::
|
page for the poll. Let's write that view::
|
||||||
|
|
||||||
def results(request, poll_id):
|
def results(request, poll_id):
|
||||||
p = get_object_or_404(polls, pk=poll_id)
|
p = get_object_or_404(Poll, pk=poll_id)
|
||||||
return render_to_response('polls/results', {'poll': p})
|
return render_to_response('polls/results', {'poll': p})
|
||||||
|
|
||||||
This is almost exactly the same as the ``detail()`` view from `Tutorial 3`_.
|
This is almost exactly the same as the ``detail()`` view from `Tutorial 3`_.
|
||||||
@ -168,10 +168,10 @@ so far::
|
|||||||
Change it like so::
|
Change it like so::
|
||||||
|
|
||||||
from django.conf.urls.defaults import *
|
from django.conf.urls.defaults import *
|
||||||
|
from myproject.polls.models import Poll
|
||||||
|
|
||||||
info_dict = {
|
info_dict = {
|
||||||
'app_label': 'polls',
|
'queryset': Poll.objects.all(),
|
||||||
'module_name': 'polls',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
@ -185,10 +185,8 @@ We're using two generic views here: ``object_list`` and ``object_detail``.
|
|||||||
Respectively, those two views abstract the concepts of "display a list of
|
Respectively, those two views abstract the concepts of "display a list of
|
||||||
objects" and "display a detail page for a particular type of object."
|
objects" and "display a detail page for a particular type of object."
|
||||||
|
|
||||||
* Each generic view needs to know which ``app_label`` and ``module_name``
|
* Each generic view needs to know which model its acting on. This
|
||||||
it's acting on. Thus, we've defined ``info_dict``, a dictionary that's
|
is done using a QuerySet.
|
||||||
passed to each of the generic views via the third parameter to the URL
|
|
||||||
tuples.
|
|
||||||
|
|
||||||
* The ``object_detail`` generic view expects that the ID value captured
|
* The ``object_detail`` generic view expects that the ID value captured
|
||||||
from the URL is called ``"object_id"``, so we've changed ``poll_id`` to
|
from the URL is called ``"object_id"``, so we've changed ``poll_id`` to
|
||||||
|
Loading…
x
Reference in New Issue
Block a user