mirror of
https://github.com/django/django.git
synced 2025-10-24 06:06:09 +00:00
Fixed #6735 -- Added class-based views.
This patch is the result of the work of many people, over many years. To try and thank individuals would inevitably lead to many people being left out or forgotten -- so rather than try to give a list that will inevitably be incomplete, I'd like to thank *everybody* who contributed in any way, big or small, with coding, testing, feedback and/or documentation over the multi-year process of getting this into trunk. git-svn-id: http://code.djangoproject.com/svn/django/trunk@14254 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
@@ -232,6 +232,7 @@ tutorial so far::
|
||||
Change it like so::
|
||||
|
||||
from django.conf.urls.defaults import *
|
||||
from django.views.generic import DetailView, ListView
|
||||
from polls.models import Poll
|
||||
|
||||
info_dict = {
|
||||
@@ -239,88 +240,91 @@ Change it like so::
|
||||
}
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^$', 'django.views.generic.list_detail.object_list', info_dict),
|
||||
(r'^(?P<object_id>\d+)/$', 'django.views.generic.list_detail.object_detail', info_dict),
|
||||
url(r'^(?P<object_id>\d+)/results/$', 'django.views.generic.list_detail.object_detail', dict(info_dict, template_name='polls/results.html'), 'poll_results'),
|
||||
(r'^$',
|
||||
ListView.as_view(
|
||||
models=Poll,
|
||||
context_object_name='latest_poll_list'
|
||||
template_name='polls/index.html')),
|
||||
(r'^(?P<pk>\d+)/$',
|
||||
DetailView.as_view(
|
||||
models=Poll,
|
||||
template_name='polls/detail.html')),
|
||||
url(r'^(?P<pk>\d+)/results/$',
|
||||
DetailView.as_view(
|
||||
models=Poll,
|
||||
template_name='polls/results.html'),
|
||||
'poll_results'),
|
||||
(r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
|
||||
)
|
||||
|
||||
We're using two generic views here:
|
||||
:func:`~django.views.generic.list_detail.object_list` and
|
||||
:func:`~django.views.generic.list_detail.object_detail`. Respectively, those two
|
||||
views abstract the concepts of "display a list of objects" and "display a detail
|
||||
page for a particular type of object."
|
||||
:class:`~django.views.generic.list.ListView` and
|
||||
:class:`~django.views.generic.detail.DetailView`. Respectively, those
|
||||
two views abstract the concepts of "display a list of objects" and
|
||||
"display a detail page for a particular type of object."
|
||||
|
||||
* Each generic view needs to know what data it will be acting upon. This
|
||||
data is provided in a dictionary. The ``queryset`` key in this dictionary
|
||||
points to the list of objects to be manipulated by the generic view.
|
||||
* Each generic view needs to know what model it will be acting
|
||||
upon. This is provided using the ``model`` parameter.
|
||||
|
||||
* The :func:`~django.views.generic.list_detail.object_detail` generic view
|
||||
expects the ID value captured from the URL to be called ``"object_id"``,
|
||||
so we've changed ``poll_id`` to ``object_id`` for the generic views.
|
||||
* The :class:`~django.views.generic.list.DetailView` generic view
|
||||
expects the primary key value captured from the URL to be called
|
||||
``"pk"``, so we've changed ``poll_id`` to ``pk`` for the generic
|
||||
views.
|
||||
|
||||
* We've added a name, ``poll_results``, to the results view so that we have
|
||||
a way to refer to its URL later on (see the documentation about
|
||||
:ref:`naming URL patterns <naming-url-patterns>` for information). We're
|
||||
also using the :func:`~django.conf.urls.default.url` function from
|
||||
* We've added a name, ``poll_results``, to the results view so
|
||||
that we have a way to refer to its URL later on (see the
|
||||
documentation about :ref:`naming URL patterns
|
||||
<naming-url-patterns>` for information). We're also using the
|
||||
:func:`~django.conf.urls.default.url` function from
|
||||
:mod:`django.conf.urls.defaults` here. It's a good habit to use
|
||||
:func:`~django.conf.urls.defaults.url` when you are providing a pattern
|
||||
name like this.
|
||||
:func:`~django.conf.urls.defaults.url` when you are providing a
|
||||
pattern name like this.
|
||||
|
||||
By default, the :func:`~django.views.generic.list_detail.object_detail` generic
|
||||
view uses a template called ``<app name>/<model name>_detail.html``. In our
|
||||
case, it'll use the template ``"polls/poll_detail.html"``. Thus, rename your
|
||||
``polls/detail.html`` template to ``polls/poll_detail.html``, and change the
|
||||
:func:`~django.shortcuts.render_to_response` line in ``vote()``.
|
||||
By default, the :class:`~django.views.generic.list.DetailView` generic
|
||||
view uses a template called ``<app name>/<model name>_detail.html``.
|
||||
In our case, it'll use the template ``"polls/poll_detail.html"``. The
|
||||
``template_name`` argument is used to tell Django to use a specific
|
||||
template name instead of the autogenerated default template name. We
|
||||
also specify the ``template_name`` for the ``results`` list view --
|
||||
this ensures that the results view and the detail view have a
|
||||
different appearance when rendered, even though they're both a
|
||||
:class:`~django.views.generic.list.DetailView` behind the scenes.
|
||||
|
||||
Similarly, the :func:`~django.views.generic.list_detail.object_list` generic
|
||||
view uses a template called ``<app name>/<model name>_list.html``. Thus, rename
|
||||
``polls/index.html`` to ``polls/poll_list.html``.
|
||||
Similarly, the :class:`~django.views.generic.list.ListView` generic
|
||||
view uses a default template called ``<app name>/<model
|
||||
name>_list.html``; we use ``template_name`` to tell
|
||||
:class:`~django.views.generic.list.ListView` to use our existing
|
||||
``"polls/index.html"`` template.
|
||||
|
||||
Because we have more than one entry in the URLconf that uses
|
||||
:func:`~django.views.generic.list_detail.object_detail` for the polls app, we
|
||||
manually specify a template name for the results view:
|
||||
``template_name='polls/results.html'``. Otherwise, both views would use the same
|
||||
template. Note that we use ``dict()`` to return an altered dictionary in place.
|
||||
In previous parts of the tutorial, the templates have been provided
|
||||
with a context that contains the ``poll`` and ``latest_poll_list``
|
||||
context variables. For DetailView the ``poll`` variable is provided
|
||||
automatically -- since we're using a Django model (``Poll``), Django
|
||||
is able to determine an appropriate name for the context variable.
|
||||
However, for ListView, the automatically generated context variable is
|
||||
``poll_list``. To override this we provide the ``context_object_name``
|
||||
option, specifying that we want to use ``latest_poll_list`` instead.
|
||||
As an alternative approach, you could change your templates to match
|
||||
the new default context variables -- but it's a lot easier to just
|
||||
tell Django to use the variable you want.
|
||||
|
||||
.. note:: :meth:`django.db.models.QuerySet.all` is lazy
|
||||
You can now delete the ``index()``, ``detail()`` and ``results()``
|
||||
views from ``polls/views.py``. We don't need them anymore -- they have
|
||||
been replaced by generic views.
|
||||
|
||||
It might look a little frightening to see ``Poll.objects.all()`` being used
|
||||
in a detail view which only needs one ``Poll`` object, but don't worry;
|
||||
``Poll.objects.all()`` is actually a special object called a
|
||||
:class:`~django.db.models.QuerySet`, which is "lazy" and doesn't hit your
|
||||
database until it absolutely has to. By the time the database query happens,
|
||||
the :func:`~django.views.generic.list_detail.object_detail` generic view
|
||||
will have narrowed its scope down to a single object, so the eventual query
|
||||
will only select one row from the database.
|
||||
The ``vote()`` view is still required. However, it must be modified to
|
||||
match the new context variables. In the
|
||||
:func:`~django.shortcuts.render_to_response` call, rename the ``poll``
|
||||
context variable to ``object``.
|
||||
|
||||
If you'd like to know more about how that works, The Django database API
|
||||
documentation :ref:`explains the lazy nature of QuerySet objects
|
||||
<querysets-are-lazy>`.
|
||||
|
||||
In previous parts of the tutorial, the templates have been provided with a
|
||||
context that contains the ``poll`` and ``latest_poll_list`` context variables.
|
||||
However, the generic views provide the variables ``object`` and ``object_list``
|
||||
as context. Therefore, you need to change your templates to match the new
|
||||
context variables. Go through your templates, and modify any reference to
|
||||
``latest_poll_list`` to ``object_list``, and change any reference to ``poll``
|
||||
to ``object``.
|
||||
|
||||
You can now delete the ``index()``, ``detail()`` and ``results()`` views
|
||||
from ``polls/views.py``. We don't need them anymore -- they have been replaced
|
||||
by generic views.
|
||||
|
||||
The ``vote()`` view is still required. However, it must be modified to match the
|
||||
new context variables. In the :func:`~django.shortcuts.render_to_response` call,
|
||||
rename the ``poll`` context variable to ``object``.
|
||||
|
||||
The last thing to do is fix the URL handling to account for the use of generic
|
||||
views. In the vote view above, we used the
|
||||
:func:`~django.core.urlresolvers.reverse` function to avoid hard-coding our
|
||||
URLs. Now that we've switched to a generic view, we'll need to change the
|
||||
:func:`~django.core.urlresolvers.reverse` call to point back to our new generic
|
||||
view. We can't simply use the view function anymore -- generic views can be (and
|
||||
are) used multiple times -- but we can use the name we've given::
|
||||
The last thing to do is fix the URL handling to account for the use of
|
||||
generic views. In the vote view above, we used the
|
||||
:func:`~django.core.urlresolvers.reverse` function to avoid
|
||||
hard-coding our URLs. Now that we've switched to a generic view, we'll
|
||||
need to change the :func:`~django.core.urlresolvers.reverse` call to
|
||||
point back to our new generic view. We can't simply use the view
|
||||
function anymore -- generic views can be (and are) used multiple times
|
||||
-- but we can use the name we've given::
|
||||
|
||||
return HttpResponseRedirect(reverse('poll_results', args=(p.id,)))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user