1
0
mirror of https://github.com/django/django.git synced 2025-10-23 21:59:11 +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:
Russell Keith-Magee
2010-10-18 13:34:47 +00:00
parent fa2159f85b
commit 0fcb094557
55 changed files with 5020 additions and 74 deletions

View File

@@ -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,)))