1
0
mirror of https://github.com/django/django.git synced 2025-10-31 09:41:08 +00:00

Merged recent changes from trunk.

This commit is contained in:
Russell Keith-Magee
2012-08-20 13:09:09 +08:00
940 changed files with 21954 additions and 15445 deletions

View File

@@ -64,11 +64,8 @@ Fields
.. attribute:: models.User.username
Required. 30 characters or fewer. Alphanumeric characters only
(letters, digits and underscores).
.. versionchanged:: 1.2
Usernames may now contain ``@``, ``+``, ``.`` and ``-`` characters.
Required. 30 characters or fewer. Usernames may contain alphanumeric,
``_``, ``@``, ``+``, ``.`` and ``-`` characters.
.. attribute:: models.User.first_name
@@ -101,12 +98,13 @@ Fields
This doesn't necessarily control whether or not the user can log in.
Authentication backends aren't required to check for the ``is_active``
flag, so if you want to reject a login based on ``is_active`` being
``False``, it's up to you to check that in your own login view.
However, the :class:`~django.contrib.auth.forms.AuthenticationForm`
used by the :func:`~django.contrib.auth.views.login` view *does*
perform this check, as do the permission-checking methods such as
:meth:`~models.User.has_perm` and the authentication in the Django
flag, and the default backends do not. If you want to reject a login
based on ``is_active`` being ``False``, it's up to you to check that in
your own login view or a custom authentication backend. However, the
:class:`~django.contrib.auth.forms.AuthenticationForm` used by the
:func:`~django.contrib.auth.views.login` view (which is the default)
*does* perform this check, as do the permission-checking methods such
as :meth:`~models.User.has_perm` and the authentication in the Django
admin. All of those functions/methods will return ``False`` for
inactive users.
@@ -207,8 +205,6 @@ Methods
Returns a set of permission strings that the user has, through his/her
groups.
.. versionadded:: 1.2
If ``obj`` is passed in, only returns the group permissions for
this specific object.
@@ -217,8 +213,6 @@ Methods
Returns a set of permission strings that the user has, both through
group and user permissions.
.. versionadded:: 1.2
If ``obj`` is passed in, only returns the permissions for this
specific object.
@@ -229,8 +223,6 @@ Methods
`permissions`_ section below). If the user is inactive, this method will
always return ``False``.
.. versionadded:: 1.2
If ``obj`` is passed in, this method won't check for a permission for
the model, but for this specific object.
@@ -241,8 +233,6 @@ Methods
``"<app label>.<permission codename>"``. If the user is inactive,
this method will always return ``False``.
.. versionadded:: 1.2
If ``obj`` is passed in, this method won't check for permissions for
the model, but for the specific object.
@@ -349,9 +339,6 @@ Django requires add *and* change permissions as a slight security measure.
Changing passwords
~~~~~~~~~~~~~~~~~~
.. versionadded:: 1.2
The ``manage.py changepassword`` command was added.
:djadmin:`manage.py changepassword *username* <changepassword>` offers a method
of changing a User's password from the command line. It prompts you to
change the password of a given user which you must enter twice. If
@@ -1046,8 +1033,6 @@ The login_required decorator
{% endblock %}
.. versionadded:: 1.2
If you are using alternate authentication (see
:ref:`authentication-backends`) you can pass a custom authentication form
to the login view via the ``authentication_form`` parameter. This form must
@@ -1140,8 +1125,6 @@ includes a few other useful built-in views located in
* ``post_change_redirect``: The URL to redirect to after a successful
password change.
.. versionadded:: 1.2
* ``password_change_form``: A custom "change password" form which must
accept a ``user`` keyword argument. The form is responsible for
actually changing the user's password. Defaults to
@@ -1465,12 +1448,13 @@ The permission_required decorator
.. currentmodule:: django.contrib.auth
Limiting access to generic views
--------------------------------
Applying permissions to generic views
-------------------------------------
To limit access to a :doc:`class-based generic view </ref/class-based-views>`,
decorate the :meth:`View.dispatch <django.views.generic.base.View.dispatch>`
method on the class. See :ref:`decorating-class-based-views` for details.
To apply a permission to a :doc:`class-based generic view
</ref/class-based-views/index>`, decorate the :meth:`View.dispatch
<django.views.generic.base.View.dispatch>` method on the class. See
:ref:`decorating-class-based-views` for details.
.. _permissions:
@@ -1493,12 +1477,13 @@ The Django admin site uses permissions as follows:
* Access to delete an object is limited to users with the "delete"
permission for that type of object.
Permissions are set globally per type of object, not per specific object
instance. For example, it's possible to say "Mary may change news stories," but
it's not currently possible to say "Mary may change news stories, but only the
ones she created herself" or "Mary may only change news stories that have a
certain status, publication date or ID." The latter functionality is something
Django developers are currently discussing.
Permissions can be set not only per type of object, but also per specific
object instance. By using the
:meth:`~django.contrib.admin.ModelAdmin.has_add_permission`,
:meth:`~django.contrib.admin.ModelAdmin.has_change_permission` and
:meth:`~django.contrib.admin.ModelAdmin.has_delete_permission` methods provided
by the :class:`~django.contrib.admin.ModelAdmin` class, it is possible to
customize permissions for different object instances of the same type.
Default permissions
-------------------
@@ -1771,7 +1756,11 @@ By default, :setting:`AUTHENTICATION_BACKENDS` is set to::
('django.contrib.auth.backends.ModelBackend',)
That's the basic authentication scheme that checks the Django users database.
That's the basic authentication backend that checks the Django users database
and queries the builtin permissions. It does not provide protection against
brute force attacks via any rate limiting mechanism. You may either implement
your own rate limiting mechanism in a custom auth backend, or use the
mechanisms provided by most Web servers.
The order of :setting:`AUTHENTICATION_BACKENDS` matters, so if the same
username and password is valid in multiple backends, Django will stop
@@ -1791,8 +1780,9 @@ processing at the first positive match.
Writing an authentication backend
---------------------------------
An authentication backend is a class that implements two methods:
``get_user(user_id)`` and ``authenticate(**credentials)``.
An authentication backend is a class that implements two required methods:
``get_user(user_id)`` and ``authenticate(**credentials)``, as well as a set of
optional permission related :ref:`authorization methods <authorization_methods>`.
The ``get_user`` method takes a ``user_id`` -- which could be a username,
database ID or whatever -- and returns a ``User`` object.
@@ -1861,6 +1851,8 @@ object the first time a user authenticates::
except User.DoesNotExist:
return None
.. _authorization_methods:
Handling authorization in custom backends
-----------------------------------------
@@ -1891,13 +1883,16 @@ fairly simply::
return False
This gives full permissions to the user granted access in the above example.
Notice that the backend auth functions all take the user object as an argument,
and they also accept the same arguments given to the associated
:class:`django.contrib.auth.models.User` functions.
Notice that in addition to the same arguments given to the associated
:class:`django.contrib.auth.models.User` functions, the backend auth functions
all take the user object, which may be an anonymous user, as an argument.
A full authorization implementation can be found in
`django/contrib/auth/backends.py`_, which is the default backend and queries
the ``auth_permission`` table most of the time.
A full authorization implementation can be found in the ``ModelBackend`` class
in `django/contrib/auth/backends.py`_, which is the default backend and queries
the ``auth_permission`` table most of the time. If you wish to provide
custom behavior for only part of the backend API, you can take advantage of
Python inheritence and subclass ``ModelBackend`` instead of implementing the
complete API in a custom backend.
.. _django/contrib/auth/backends.py: https://github.com/django/django/blob/master/django/contrib/auth/backends.py
@@ -1906,8 +1901,6 @@ the ``auth_permission`` table most of the time.
Authorization for anonymous users
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionchanged:: 1.2
An anonymous user is one that is not authenticated i.e. they have provided no
valid authentication details. However, that does not necessarily mean they are
not authorized to do anything. At the most basic level, most Web sites
@@ -1915,25 +1908,27 @@ authorize anonymous users to browse most of the site, and many allow anonymous
posting of comments etc.
Django's permission framework does not have a place to store permissions for
anonymous users. However, it has a foundation that allows custom authentication
backends to specify authorization for anonymous users. This is especially useful
for the authors of re-usable apps, who can delegate all questions of authorization
to the auth backend, rather than needing settings, for example, to control
anonymous access.
anonymous users. However, the user object passed to an authentication backend
may be an :class:`django.contrib.auth.models.AnonymousUser` object, allowing
the backend to specify custom authorization behavior for anonymous users. This
is especially useful for the authors of re-usable apps, who can delegate all
questions of authorization to the auth backend, rather than needing settings,
for example, to control anonymous access.
.. _inactive_auth:
Authorization for inactive users
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 1.3
.. versionchanged:: 1.3
An inactive user is a one that is authenticated but has its attribute
``is_active`` set to ``False``. However this does not mean they are not
authorized to do anything. For example they are allowed to activate their
account.
The support for anonymous users in the permission system allows for
anonymous users to have permissions to do something while inactive
The support for anonymous users in the permission system allows for a scenario
where anonymous users have permissions to do something while inactive
authenticated users do not.
Do not forget to test for the ``is_active`` attribute of the user in your own
@@ -1941,9 +1936,11 @@ backend permission methods.
Handling object permissions
---------------------------
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Django's permission framework has a foundation for object permissions, though
there is no implementation for it in the core. That means that checking for
object permissions will always return ``False`` or an empty list (depending on
the check performed).
the check performed). An authentication backend will receive the keyword
parameters ``obj`` and ``user_obj`` for each object related authorization
method and can return the object level permission as appropriate.

View File

@@ -83,12 +83,6 @@ two most common are `python-memcached`_ and `pylibmc`_.
.. _`python-memcached`: ftp://ftp.tummy.com/pub/python-memcached/
.. _`pylibmc`: http://sendapatch.se/projects/pylibmc/
.. versionchanged:: 1.2
In Django 1.0 and 1.1, you could also use ``cmemcache`` as a binding.
However, support for this library was deprecated in 1.2 due to
a lack of maintenance on the ``cmemcache`` library itself. Support for
``cmemcache`` will be removed completely in Django 1.4.
.. versionchanged:: 1.3
Support for ``pylibmc`` was added.
@@ -493,8 +487,6 @@ more on these decorators.
.. _i18n-cache-key:
.. versionadded:: 1.2
If :setting:`USE_I18N` is set to ``True`` then the generated cache key will
include the name of the active :term:`language<language code>` -- see also
:ref:`how-django-discovers-language-preference`). This allows you to easily
@@ -603,7 +595,8 @@ the ``cache`` template tag. To give your template access to this tag, put
The ``{% cache %}`` template tag caches the contents of the block for a given
amount of time. It takes at least two arguments: the cache timeout, in seconds,
and the name to give the cache fragment. For example:
and the name to give the cache fragment. The name will be taken as is, do not
use a variable. For example:
.. code-block:: html+django
@@ -737,8 +730,6 @@ actually exist in the cache (and haven't expired)::
>>> cache.get_many(['a', 'b', 'c'])
{'a': 1, 'b': 2, 'c': 3}
.. versionadded:: 1.2
To set multiple values more efficiently, use ``set_many()`` to pass a dictionary
of key-value pairs::
@@ -753,15 +744,11 @@ clearing the cache for a particular object::
>>> cache.delete('a')
.. versionadded:: 1.2
If you want to clear a bunch of keys at once, ``delete_many()`` can take a list
of keys to be cleared::
>>> cache.delete_many(['a', 'b', 'c'])
.. versionadded:: 1.2
Finally, if you want to delete all the keys in the cache, use
``cache.clear()``. Be careful with this; ``clear()`` will remove *everything*
from the cache, not just the keys set by your application. ::
@@ -877,7 +864,7 @@ key version to provide a final cache key. By default, the three parts
are joined using colons to produce a final string::
def make_key(key, key_prefix, version):
return ':'.join([key_prefix, str(version), smart_str(key)])
return ':'.join([key_prefix, str(version), smart_bytes(key)])
If you want to combine the parts in different ways, or apply other
processing to the final key (e.g., taking a hash digest of the key

View File

@@ -1,624 +0,0 @@
=========================
Class-based generic views
=========================
.. versionadded:: 1.3
.. note::
Prior to Django 1.3, generic views were implemented as functions. The
function-based implementation has been removed in favor of the
class-based approach described here.
Writing Web applications can be monotonous, because we repeat certain patterns
again and again. Django tries to take away some of that monotony at the model
and template layers, but Web developers also experience this boredom at the view
level.
Django's *generic views* were developed to ease that pain. They take certain
common idioms and patterns found in view development and abstract them so that
you can quickly write common views of data without having to write too much
code.
We can recognize certain common tasks, like displaying a list of objects, and
write code that displays a list of *any* object. Then the model in question can
be passed as an extra argument to the URLconf.
Django ships with generic views to do the following:
* Perform common "simple" tasks: redirect to a different page and
render a given template.
* Display list and detail pages for a single object. If we were creating an
application to manage conferences then a ``TalkListView`` and a
``RegisteredUserListView`` would be examples of list views. A single
talk page is an example of what we call a "detail" view.
* Present date-based objects in year/month/day archive pages,
associated detail, and "latest" pages.
* Allow users to create, update, and delete objects -- with or
without authorization.
Taken together, these views provide easy interfaces to perform the most common
tasks developers encounter.
Simple usage
============
Class-based generic views (and any class-based views that inherit from
the base classes Django provides) can be configured in two
ways: subclassing, or passing in arguments directly in the URLconf.
When you subclass a class-based view, you can override attributes
(such as the ``template_name``) or methods (such as ``get_context_data``)
in your subclass to provide new values or methods. Consider, for example,
a view that just displays one template, ``about.html``. Django has a
generic view to do this - :class:`~django.views.generic.base.TemplateView` -
so we can just subclass it, and override the template name::
# some_app/views.py
from django.views.generic import TemplateView
class AboutView(TemplateView):
template_name = "about.html"
Then, we just need to add this new view into our URLconf. As the class-based
views themselves are classes, we point the URL to the ``as_view`` class method
instead, which is the entry point for class-based views::
# urls.py
from django.conf.urls import patterns, url, include
from some_app.views import AboutView
urlpatterns = patterns('',
(r'^about/', AboutView.as_view()),
)
Alternatively, if you're only changing a few simple attributes on a
class-based view, you can simply pass the new attributes into the ``as_view``
method call itself::
from django.conf.urls import patterns, url, include
from django.views.generic import TemplateView
urlpatterns = patterns('',
(r'^about/', TemplateView.as_view(template_name="about.html")),
)
A similar overriding pattern can be used for the ``url`` attribute on
:class:`~django.views.generic.base.RedirectView`, another simple
generic view.
Generic views of objects
========================
:class:`~django.views.generic.base.TemplateView` certainly is useful,
but Django's generic views really shine when it comes to presenting
views of your database content. Because it's such a common task,
Django comes with a handful of built-in generic views that make
generating list and detail views of objects incredibly easy.
Let's take a look at one of these generic views: the "object list" view. We'll
be using these models::
# models.py
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Meta:
ordering = ["-name"]
def __unicode__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField('Author')
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
To build a list page of all publishers, we'd use a URLconf along these lines::
from django.conf.urls import patterns, url, include
from django.views.generic import ListView
from books.models import Publisher
urlpatterns = patterns('',
(r'^publishers/$', ListView.as_view(
model=Publisher,
)),
)
That's all the Python code we need to write. We still need to write a template,
however. We could explicitly tell the view which template to use
by including a ``template_name`` key in the arguments to as_view, but in
the absence of an explicit template Django will infer one from the object's
name. In this case, the inferred template will be
``"books/publisher_list.html"`` -- the "books" part comes from the name of the
app that defines the model, while the "publisher" bit is just the lowercased
version of the model's name.
.. note::
Thus, when (for example) the :class:`django.template.loaders.app_directories.Loader`
template loader is enabled in :setting:`TEMPLATE_LOADERS`, the template
location would be::
/path/to/project/books/templates/books/publisher_list.html
.. highlightlang:: html+django
This template will be rendered against a context containing a variable called
``object_list`` that contains all the publisher objects. A very simple template
might look like the following::
{% extends "base.html" %}
{% block content %}
<h2>Publishers</h2>
<ul>
{% for publisher in object_list %}
<li>{{ publisher.name }}</li>
{% endfor %}
</ul>
{% endblock %}
That's really all there is to it. All the cool features of generic views come
from changing the "info" dictionary passed to the generic view. The
:doc:`generic views reference</ref/class-based-views>` documents all the generic
views and their options in detail; the rest of this document will consider
some of the common ways you might customize and extend generic views.
Extending generic views
=======================
.. highlightlang:: python
There's no question that using generic views can speed up development
substantially. In most projects, however, there comes a moment when the
generic views no longer suffice. Indeed, the most common question asked by new
Django developers is how to make generic views handle a wider array of
situations.
This is one of the reasons generic views were redesigned for the 1.3 release -
previously, they were just view functions with a bewildering array of options;
now, rather than passing in a large amount of configuration in the URLconf,
the recommended way to extend generic views is to subclass them, and override
their attributes or methods.
Making "friendly" template contexts
-----------------------------------
You might have noticed that our sample publisher list template stores
all the publishers in a variable named ``object_list``. While this
works just fine, it isn't all that "friendly" to template authors:
they have to "just know" that they're dealing with publishers here.
Well, if you're dealing with a model object, this is already done for
you. When you are dealing with an object or queryset, Django is able
to populate the context using the verbose name (or the plural verbose
name, in the case of a list of objects) of the object being displayed.
This is provided in addition to the default ``object_list`` entry, but
contains exactly the same data.
If the verbose name (or plural verbose name) still isn't a good match,
you can manually set the name of the context variable. The
``context_object_name`` attribute on a generic view specifies the
context variable to use. In this example, we'll override it in the
URLconf, since it's a simple change:
.. parsed-literal::
urlpatterns = patterns('',
(r'^publishers/$', ListView.as_view(
model=Publisher,
**context_object_name="publisher_list",**
)),
)
Providing a useful ``context_object_name`` is always a good idea. Your
coworkers who design templates will thank you.
Adding extra context
--------------------
Often you simply need to present some extra information beyond that
provided by the generic view. For example, think of showing a list of
all the books on each publisher detail page. The
:class:`~django.views.generic.detail.DetailView` generic view provides
the publisher to the context, but it seems there's no way to get
additional information in that template.
However, there is; you can subclass
:class:`~django.views.generic.detail.DetailView` and provide your own
implementation of the ``get_context_data`` method. The default
implementation of this that comes with
:class:`~django.views.generic.detail.DetailView` simply adds in the
object being displayed to the template, but you can override it to show
more::
from django.views.generic import DetailView
from books.models import Publisher, Book
class PublisherDetailView(DetailView):
context_object_name = "publisher"
model = Publisher
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(PublisherDetailView, self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['book_list'] = Book.objects.all()
return context
.. note::
Generally, get_context_data will merge the context data of all parent classes
with those of the current class. To preserve this behavior in your own classes
where you want to alter the context, you should be sure to call
get_context_data on the super class. When no two classes try to define the same
key, this will give the expected results. However if any class attempts to
override a key after parent classes have set it (after the call to super), any
children of that class will also need to explictly set it after super if they
want to be sure to override all parents.
Viewing subsets of objects
--------------------------
Now let's take a closer look at the ``model`` argument we've been
using all along. The ``model`` argument, which specifies the database
model that the view will operate upon, is available on all the
generic views that operate on a single object or a collection of
objects. However, the ``model`` argument is not the only way to
specify the objects that the view will operate upon -- you can also
specify the list of objects using the ``queryset`` argument::
from django.views.generic import DetailView
from books.models import Publisher, Book
class PublisherDetailView(DetailView):
context_object_name = "publisher"
queryset = Publisher.objects.all()
Specifying ``model = Publisher`` is really just shorthand for saying
``queryset = Publisher.objects.all()``. However, by using ``queryset``
to define a filtered list of objects you can be more specific about the
objects that will be visible in the view (see :doc:`/topics/db/queries`
for more information about :class:`QuerySet` objects, and see the
:doc:`class-based views reference </ref/class-based-views>` for the complete
details).
To pick a simple example, we might want to order a list of books by
publication date, with the most recent first::
urlpatterns = patterns('',
(r'^publishers/$', ListView.as_view(
queryset=Publisher.objects.all(),
context_object_name="publisher_list",
)),
(r'^books/$', ListView.as_view(
queryset=Book.objects.order_by("-publication_date"),
context_object_name="book_list",
)),
)
That's a pretty simple example, but it illustrates the idea nicely. Of course,
you'll usually want to do more than just reorder objects. If you want to
present a list of books by a particular publisher, you can use the same
technique (here, illustrated using subclassing rather than by passing arguments
in the URLconf)::
from django.views.generic import ListView
from books.models import Book
class AcmeBookListView(ListView):
context_object_name = "book_list"
queryset = Book.objects.filter(publisher__name="Acme Publishing")
template_name = "books/acme_list.html"
Notice that along with a filtered ``queryset``, we're also using a custom
template name. If we didn't, the generic view would use the same template as the
"vanilla" object list, which might not be what we want.
Also notice that this isn't a very elegant way of doing publisher-specific
books. If we want to add another publisher page, we'd need another handful of
lines in the URLconf, and more than a few publishers would get unreasonable.
We'll deal with this problem in the next section.
.. note::
If you get a 404 when requesting ``/books/acme/``, check to ensure you
actually have a Publisher with the name 'ACME Publishing'. Generic
views have an ``allow_empty`` parameter for this case. See the
:doc:`class-based-views reference</ref/class-based-views>` for more details.
Dynamic filtering
-----------------
Another common need is to filter down the objects given in a list page by some
key in the URL. Earlier we hard-coded the publisher's name in the URLconf, but
what if we wanted to write a view that displayed all the books by some arbitrary
publisher?
Handily, the ``ListView`` has a
:meth:`~django.views.generic.detail.ListView.get_queryset` method we can
override. Previously, it has just been returning the value of the ``queryset``
attribute, but now we can add more logic.
The key part to making this work is that when class-based views are called,
various useful things are stored on ``self``; as well as the request
(``self.request``) this includes the positional (``self.args``) and name-based
(``self.kwargs``) arguments captured according to the URLconf.
Here, we have a URLconf with a single captured group::
from books.views import PublisherBookListView
urlpatterns = patterns('',
(r'^books/(\w+)/$', PublisherBookListView.as_view()),
)
Next, we'll write the ``PublisherBookListView`` view itself::
from django.shortcuts import get_object_or_404
from django.views.generic import ListView
from books.models import Book, Publisher
class PublisherBookListView(ListView):
context_object_name = "book_list"
template_name = "books/books_by_publisher.html"
def get_queryset(self):
publisher = get_object_or_404(Publisher, name__iexact=self.args[0])
return Book.objects.filter(publisher=publisher)
As you can see, it's quite easy to add more logic to the queryset selection;
if we wanted, we could use ``self.request.user`` to filter using the current
user, or other more complex logic.
We can also add the publisher into the context at the same time, so we can
use it in the template::
class PublisherBookListView(ListView):
context_object_name = "book_list"
template_name = "books/books_by_publisher.html"
def get_queryset(self):
self.publisher = get_object_or_404(Publisher, name__iexact=self.args[0])
return Book.objects.filter(publisher=self.publisher)
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(PublisherBookListView, self).get_context_data(**kwargs)
# Add in the publisher
context['publisher'] = self.publisher
return context
Performing extra work
---------------------
The last common pattern we'll look at involves doing some extra work before
or after calling the generic view.
Imagine we had a ``last_accessed`` field on our ``Author`` object that we were
using to keep track of the last time anybody looked at that author::
# models.py
class Author(models.Model):
salutation = models.CharField(max_length=10)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=40)
email = models.EmailField()
headshot = models.ImageField(upload_to='/tmp')
last_accessed = models.DateTimeField()
The generic ``DetailView`` class, of course, wouldn't know anything about this
field, but once again we could easily write a custom view to keep that field
updated.
First, we'd need to add an author detail bit in the URLconf to point to a
custom view:
.. parsed-literal::
from books.views import AuthorDetailView
urlpatterns = patterns('',
#...
**(r'^authors/(?P<pk>\\d+)/$', AuthorDetailView.as_view()),**
)
Then we'd write our new view -- ``get_object`` is the method that retrieves the
object -- so we simply override it and wrap the call::
import datetime
from books.models import Author
from django.views.generic import DetailView
from django.shortcuts import get_object_or_404
class AuthorDetailView(DetailView):
queryset = Author.objects.all()
def get_object(self):
# Call the superclass
object = super(AuthorDetailView, self).get_object()
# Record the last accessed date
object.last_accessed = datetime.datetime.now()
object.save()
# Return the object
return object
.. note::
This code won't actually work unless you create a
``books/author_detail.html`` template.
.. note::
The URLconf here uses the named group ``pk`` - this name is the default
name that ``DetailView`` uses to find the value of the primary key used to
filter the queryset.
If you want to change it, you'll need to do your own ``get()`` call
on ``self.queryset`` using the new named parameter from ``self.kwargs``.
More than just HTML
-------------------
So far, we've been focusing on rendering templates to generate
responses. However, that's not all generic views can do.
Each generic view is composed out of a series of mixins, and each
mixin contributes a little piece of the entire view. Some of these
mixins -- such as
:class:`~django.views.generic.base.TemplateResponseMixin` -- are
specifically designed for rendering content to an HTML response using a
template. However, you can write your own mixins that perform
different rendering behavior.
For example, a simple JSON mixin might look something like this::
import json
from django import http
class JSONResponseMixin(object):
def render_to_response(self, context):
"Returns a JSON response containing 'context' as payload"
return self.get_json_response(self.convert_context_to_json(context))
def get_json_response(self, content, **httpresponse_kwargs):
"Construct an `HttpResponse` object."
return http.HttpResponse(content,
content_type='application/json',
**httpresponse_kwargs)
def convert_context_to_json(self, context):
"Convert the context dictionary into a JSON object"
# Note: This is *EXTREMELY* naive; in reality, you'll need
# to do much more complex handling to ensure that arbitrary
# objects -- such as Django model instances or querysets
# -- can be serialized as JSON.
return json.dumps(context)
Then, you could build a JSON-returning
:class:`~django.views.generic.detail.DetailView` by mixing your
:class:`JSONResponseMixin` with the
:class:`~django.views.generic.detail.BaseDetailView` -- (the
:class:`~django.views.generic.detail.DetailView` before template
rendering behavior has been mixed in)::
class JSONDetailView(JSONResponseMixin, BaseDetailView):
pass
This view can then be deployed in the same way as any other
:class:`~django.views.generic.detail.DetailView`, with exactly the
same behavior -- except for the format of the response.
If you want to be really adventurous, you could even mix a
:class:`~django.views.generic.detail.DetailView` subclass that is able
to return *both* HTML and JSON content, depending on some property of
the HTTP request, such as a query argument or a HTTP header. Just mix
in both the :class:`JSONResponseMixin` and a
:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`,
and override the implementation of :func:`render_to_response()` to defer
to the appropriate subclass depending on the type of response that the user
requested::
class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView):
def render_to_response(self, context):
# Look for a 'format=json' GET argument
if self.request.GET.get('format','html') == 'json':
return JSONResponseMixin.render_to_response(self, context)
else:
return SingleObjectTemplateResponseMixin.render_to_response(self, context)
Because of the way that Python resolves method overloading, the local
``render_to_response()`` implementation will override the versions provided by
:class:`JSONResponseMixin` and
:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`.
Decorating class-based views
============================
.. highlightlang:: python
The extension of class-based views isn't limited to using mixins. You
can use also use decorators.
Decorating in URLconf
---------------------
The simplest way of decorating class-based views is to decorate the
result of the :meth:`~django.views.generic.base.View.as_view` method.
The easiest place to do this is in the URLconf where you deploy your
view::
from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView
from .views import VoteView
urlpatterns = patterns('',
(r'^about/', login_required(TemplateView.as_view(template_name="secret.html"))),
(r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),
)
This approach applies the decorator on a per-instance basis. If you
want every instance of a view to be decorated, you need to take a
different approach.
.. _decorating-class-based-views:
Decorating the class
--------------------
To decorate every instance of a class-based view, you need to decorate
the class definition itself. To do this you apply the decorator to the
:meth:`~django.views.generic.base.View.dispatch` method of the class.
A method on a class isn't quite the same as a standalone function, so
you can't just apply a function decorator to the method -- you need to
transform it into a method decorator first. The ``method_decorator``
decorator transforms a function decorator into a method decorator so
that it can be used on an instance method. For example::
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
class ProtectedView(TemplateView):
template_name = 'secret.html'
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(ProtectedView, self).dispatch(*args, **kwargs)
In this example, every instance of ``ProtectedView`` will have
login protection.
.. note::
``method_decorator`` passes ``*args`` and ``**kwargs``
as parameters to the decorated method on the class. If your method
does not accept a compatible set of parameters it will raise a
``TypeError`` exception.

View File

@@ -0,0 +1,432 @@
.. _Generic views:
=========================
Class-based generic views
=========================
.. note::
Prior to Django 1.3, generic views were implemented as functions. The
function-based implementation has been removed in favor of the
class-based approach described here.
Writing Web applications can be monotonous, because we repeat certain patterns
again and again. Django tries to take away some of that monotony at the model
and template layers, but Web developers also experience this boredom at the view
level.
Django's *generic views* were developed to ease that pain. They take certain
common idioms and patterns found in view development and abstract them so that
you can quickly write common views of data without having to write too much
code.
We can recognize certain common tasks, like displaying a list of objects, and
write code that displays a list of *any* object. Then the model in question can
be passed as an extra argument to the URLconf.
Django ships with generic views to do the following:
* Display list and detail pages for a single object. If we were creating an
application to manage conferences then a ``TalkListView`` and a
``RegisteredUserListView`` would be examples of list views. A single
talk page is an example of what we call a "detail" view.
* Present date-based objects in year/month/day archive pages,
associated detail, and "latest" pages.
* Allow users to create, update, and delete objects -- with or
without authorization.
Taken together, these views provide easy interfaces to perform the most common
tasks developers encounter.
Extending generic views
=======================
There's no question that using generic views can speed up development
substantially. In most projects, however, there comes a moment when the
generic views no longer suffice. Indeed, the most common question asked by new
Django developers is how to make generic views handle a wider array of
situations.
This is one of the reasons generic views were redesigned for the 1.3 release -
previously, they were just view functions with a bewildering array of options;
now, rather than passing in a large amount of configuration in the URLconf,
the recommended way to extend generic views is to subclass them, and override
their attributes or methods.
That said, generic views will have a limit. If you find you're struggling to
implement your view as a subclass of a generic view, then you may find it more
effective to write just the code you need, using your own class-based or
functional views.
More examples of generic views are available in some third party applications,
or you could write your own as needed.
Generic views of objects
========================
:class:`~django.views.generic.base.TemplateView` certainly is useful, but
Django's generic views really shine when it comes to presenting views of your
database content. Because it's such a common task, Django comes with a handful
of built-in generic views that make generating list and detail views of objects
incredibly easy.
Let's start by looking at some examples of showing a list of objects or an
individual object.
.. comment: link here to the other topic pages (form handling, date based, mixins)
We'll be using these models::
# models.py
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Meta:
ordering = ["-name"]
def __unicode__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField('Author')
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
Now we need to define a view::
# views.py
from django.views.generic import ListView
from books.models import Publisher
class PublisherList(ListView):
model = Publisher
Finally hook that view into your urls::
# urls.py
from django.conf.urls import patterns, url, include
from books.views import PublisherList
urlpatterns = patterns('',
url(r'^publishers/$', PublisherList.as_view()),
)
That's all the Python code we need to write. We still need to write a template,
however. We could explicitly tell the view which template to use by adding a
``template_name`` attribute to the view, but in the absence of an explicit
template Django will infer one from the object's name. In this case, the
inferred template will be ``"books/publisher_list.html"`` -- the "books" part
comes from the name of the app that defines the model, while the "publisher"
bit is just the lowercased version of the model's name.
.. note::
Thus, when (for example) the
:class:`django.template.loaders.app_directories.Loader` template loader is
enabled in :setting:`TEMPLATE_LOADERS`, a template location could be:
/path/to/project/books/templates/books/publisher_list.html
.. highlightlang:: html+django
This template will be rendered against a context containing a variable called
``object_list`` that contains all the publisher objects. A very simple template
might look like the following::
{% extends "base.html" %}
{% block content %}
<h2>Publishers</h2>
<ul>
{% for publisher in object_list %}
<li>{{ publisher.name }}</li>
{% endfor %}
</ul>
{% endblock %}
That's really all there is to it. All the cool features of generic views come
from changing the attributes set on the generic view. The
:doc:`generic views reference</ref/class-based-views/index>` documents all the
generic views and their options in detail; the rest of this document will
consider some of the common ways you might customize and extend generic views.
Making "friendly" template contexts
-----------------------------------
.. highlightlang:: python
You might have noticed that our sample publisher list template stores all the
publishers in a variable named ``object_list``. While this works just fine, it
isn't all that "friendly" to template authors: they have to "just know" that
they're dealing with publishers here.
Well, if you're dealing with a model object, this is already done for you. When
you are dealing with an object or queryset, Django is able to populate the
context using the lower cased version of the model class' name. This is
provided in addition to the default ``object_list`` entry, but contains exactly
the same data, i.e. ``publisher_list``.
If the this still isn't a good match, you can manually set the name of the
context variable. The ``context_object_name`` attribute on a generic view
specifies the context variable to use::
# views.py
from django.views.generic import ListView
from books.models import Publisher
class PublisherList(ListView):
model = Publisher
context_object_name = 'my_favourite_publishers'
Providing a useful ``context_object_name`` is always a good idea. Your
coworkers who design templates will thank you.
Adding extra context
--------------------
Often you simply need to present some extra information beyond that
provided by the generic view. For example, think of showing a list of
all the books on each publisher detail page. The
:class:`~django.views.generic.detail.DetailView` generic view provides
the publisher to the context, but how do we get additional information
in that template.
However, there is; you can subclass
:class:`~django.views.generic.detail.DetailView` and provide your own
implementation of the ``get_context_data`` method. The default
implementation of this that comes with
:class:`~django.views.generic.detail.DetailView` simply adds in the
object being displayed to the template, but you can override it to send
more::
from django.views.generic import DetailView
from books.models import Publisher, Book
class PublisherDetail(DetailView):
model = Publisher
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(PublisherDetail, self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['book_list'] = Book.objects.all()
return context
.. note::
Generally, get_context_data will merge the context data of all parent
classes with those of the current class. To preserve this behavior in your
own classes where you want to alter the context, you should be sure to call
get_context_data on the super class. When no two classes try to define the
same key, this will give the expected results. However if any class
attempts to override a key after parent classes have set it (after the call
to super), any children of that class will also need to explictly set it
after super if they want to be sure to override all parents. If you're
having trouble, review the method resolution order of your view.
.. _generic-views-list-subsets:
Viewing subsets of objects
--------------------------
Now let's take a closer look at the ``model`` argument we've been
using all along. The ``model`` argument, which specifies the database
model that the view will operate upon, is available on all the
generic views that operate on a single object or a collection of
objects. However, the ``model`` argument is not the only way to
specify the objects that the view will operate upon -- you can also
specify the list of objects using the ``queryset`` argument::
from django.views.generic import DetailView
from books.models import Publisher, Book
class PublisherDetail(DetailView):
context_object_name = 'publisher'
queryset = Publisher.objects.all()
Specifying ``model = Publisher`` is really just shorthand for saying
``queryset = Publisher.objects.all()``. However, by using ``queryset``
to define a filtered list of objects you can be more specific about the
objects that will be visible in the view (see :doc:`/topics/db/queries`
for more information about :class:`QuerySet` objects, and see the
:doc:`class-based views reference </ref/class-based-views/index>` for the
complete details).
To pick a simple example, we might want to order a list of books by
publication date, with the most recent first::
from django.views.generic import ListView
from books.models import Book
class BookList(ListView):
queryset = Book.objects.order_by('-publication_date')
context_object_name = 'book_list'
That's a pretty simple example, but it illustrates the idea nicely. Of course,
you'll usually want to do more than just reorder objects. If you want to
present a list of books by a particular publisher, you can use the same
technique::
from django.views.generic import ListView
from books.models import Book
class AcmeBookList(ListView):
context_object_name = 'book_list'
queryset = Book.objects.filter(publisher__name='Acme Publishing')
template_name = 'books/acme_list.html'
Notice that along with a filtered ``queryset``, we're also using a custom
template name. If we didn't, the generic view would use the same template as the
"vanilla" object list, which might not be what we want.
Also notice that this isn't a very elegant way of doing publisher-specific
books. If we want to add another publisher page, we'd need another handful of
lines in the URLconf, and more than a few publishers would get unreasonable.
We'll deal with this problem in the next section.
.. note::
If you get a 404 when requesting ``/books/acme/``, check to ensure you
actually have a Publisher with the name 'ACME Publishing'. Generic
views have an ``allow_empty`` parameter for this case. See the
:doc:`class-based-views reference</ref/class-based-views/index>` for more
details.
Dynamic filtering
-----------------
Another common need is to filter down the objects given in a list page by some
key in the URL. Earlier we hard-coded the publisher's name in the URLconf, but
what if we wanted to write a view that displayed all the books by some arbitrary
publisher?
Handily, the ``ListView`` has a
:meth:`~django.views.generic.detail.ListView.get_queryset` method we can
override. Previously, it has just been returning the value of the ``queryset``
attribute, but now we can add more logic.
The key part to making this work is that when class-based views are called,
various useful things are stored on ``self``; as well as the request
(``self.request``) this includes the positional (``self.args``) and name-based
(``self.kwargs``) arguments captured according to the URLconf.
Here, we have a URLconf with a single captured group::
# urls.py
from books.views import PublisherBookList
urlpatterns = patterns('',
(r'^books/([\w-]+)/$', PublisherBookList.as_view()),
)
Next, we'll write the ``PublisherBookList`` view itself::
# views.py
from django.shortcuts import get_object_or_404
from django.views.generic import ListView
from books.models import Book, Publisher
class PublisherBookList(ListView):
template_name = 'books/books_by_publisher.html'
def get_queryset(self):
self.publisher = get_object_or_404(Publisher, name=self.args[0])
return Book.objects.filter(publisher=self.publisher)
As you can see, it's quite easy to add more logic to the queryset selection;
if we wanted, we could use ``self.request.user`` to filter using the current
user, or other more complex logic.
We can also add the publisher into the context at the same time, so we can
use it in the template::
# ...
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(PublisherBookList, self).get_context_data(**kwargs)
# Add in the publisher
context['publisher'] = self.publisher
return context
.. _generic-views-extra-work:
Performing extra work
---------------------
The last common pattern we'll look at involves doing some extra work before
or after calling the generic view.
Imagine we had a ``last_accessed`` field on our ``Author`` object that we were
using to keep track of the last time anybody looked at that author::
# models.py
class Author(models.Model):
salutation = models.CharField(max_length=10)
name = models.CharField(max_length=200)
email = models.EmailField()
headshot = models.ImageField(upload_to='/tmp')
last_accessed = models.DateTimeField()
The generic ``DetailView`` class, of course, wouldn't know anything about this
field, but once again we could easily write a custom view to keep that field
updated.
First, we'd need to add an author detail bit in the URLconf to point to a
custom view::
from books.views import AuthorDetailView
urlpatterns = patterns('',
#...
url(r'^authors/(?P<pk>\d+)/$', AuthorDetailView.as_view(), name='author-detail'),
)
Then we'd write our new view -- ``get_object`` is the method that retrieves the
object -- so we simply override it and wrap the call::
from django.views.generic import DetailView
from django.shortcuts import get_object_or_404
from django.utils import timezone
from books.models import Author
class AuthorDetailView(DetailView):
queryset = Author.objects.all()
def get_object(self):
# Call the superclass
object = super(AuthorDetailView, self).get_object()
# Record the last accessed date
object.last_accessed = timezone.now()
object.save()
# Return the object
return object
.. note::
The URLconf here uses the named group ``pk`` - this name is the default
name that ``DetailView`` uses to find the value of the primary key used to
filter the queryset.
If you want to call the group something else, you can set ``pk_url_kwarg``
on the view. More details can be found in the reference for
:class:`~django.views.generic.detail.DetailView`

View File

@@ -0,0 +1,205 @@
Form handling with class-based views
====================================
Form processing generally has 3 paths:
* Initial GET (blank or prepopulated form)
* POST with invalid data (typically redisplay form with errors)
* POST with valid data (process the data and typically redirect)
Implementing this yourself often results in a lot of repeated
boilerplate code (see :ref:`Using a form in a
view<using-a-form-in-a-view>`). To help avoid this, Django provides a
collection of generic class-based views for form processing.
Basic Forms
-----------
Given a simple contact form::
# forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField()
message = forms.CharField(widget=forms.Textarea)
def send_email(self):
# send email using the self.cleaned_data dictionary
pass
The view can be constructed using a FormView::
# views.py
from myapp.forms import ContactForm
from django.views.generic.edit import FormView
class ContactView(FormView):
template_name = 'contact.html'
form_class = ContactForm
success_url = '/thanks/'
def form_valid(self, form):
# This method is called when valid form data has been POSTed.
# It should return an HttpResponse.
form.send_email()
return super(ContactView, self).form_valid(form)
Notes:
* FormView inherits
:class:`~django.views.generic.base.TemplateResponseMixin` so
:attr:`~django.views.generic.base.TemplateResponseMixin.template_name`
can be used here
* The default implementation for
:meth:`~django.views.generic.edit.FormView.form_valid` simply
redirects to the :attr:`success_url`
Model Forms
-----------
Generic views really shine when working with models. These generic
views will automatically create a :class:`ModelForm`, so long as they
can work out which model class to use:
* If the :attr:`model` attribute is given, that model class will be used
* If :meth:`get_object()` returns an object, the class of that object
will be used
* If a :attr:`queryset` is given, the model for that queryset will be used
Model form views provide a :meth:`form_valid()` implementation that
saves the model automatically. You can override this if you have any
special requirements; see below for examples.
You don't even need to provide a attr:`success_url` for
:class:`~django.views.generic.edit.CreateView` or
:class:`~django.views.generic.edit.UpdateView` - they will use
:meth:`get_absolute_url()` on the model object if available.
If you want to use a custom :class:`ModelForm` (for instance to add
extra validation) simply set
:attr:`~django.views.generic.edit.FormMixin.form_class` on your view.
.. note::
When specifying a custom form class, you must still specify the model,
even though the :attr:`form_class` may be a :class:`ModelForm`.
First we need to add :meth:`get_absolute_url()` to our :class:`Author`
class:
.. code-block:: python
# models.py
from django import models
from django.core.urlresolvers import reverse
class Author(models.Model):
name = models.CharField(max_length=200)
def get_absolute_url(self):
return reverse('author-detail', kwargs={'pk': self.pk})
Then we can use :class:`CreateView` and friends to do the actual
work. Notice how we're just configuring the generic class-based views
here; we don't have to write any logic ourselves::
# views.py
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy
from myapp.models import Author
class AuthorCreate(CreateView):
model = Author
class AuthorUpdate(UpdateView):
model = Author
class AuthorDelete(DeleteView):
model = Author
success_url = reverse_lazy('author-list')
.. note::
We have to use :func:`~django.core.urlresolvers.reverse_lazy` here, not
just ``reverse`` as the urls are not loaded when the file is imported.
Finally, we hook these new views into the URLconf::
# urls.py
from django.conf.urls import patterns, url
from myapp.views import AuthorCreate, AuthorUpdate, AuthorDelete
urlpatterns = patterns('',
# ...
url(r'author/add/$', AuthorCreate.as_view(), name='author_add'),
url(r'author/(?P<pk>\d+)/$', AuthorUpdate.as_view(), name='author_update'),
url(r'author/(?P<pk>\d+)/delete/$', AuthorDelete.as_view(), name='author_delete'),
)
.. note::
These views inherit :class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`
which uses :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_prefix`
to construct the
:attr:`~django.views.generic.base.TemplateResponseMixin.template_name`
based on the model.
In this example:
* :class:`CreateView` and :class:`UpdateView` use ``myapp/author_form.html``
* :class:`DeleteView` uses ``myapp/author_confirm_delete.html``
If you wish to have separate templates for :class:`CreateView` and
:class:1UpdateView`, you can set either :attr:`template_name` or
:attr:`template_name_suffix` on your view class.
Models and request.user
-----------------------
To track the user that created an object using a :class:`CreateView`,
you can use a custom :class:`ModelForm` to do this. First, add the
foreign key relation to the model::
# models.py
from django import models
from django.contrib.auth import User
class Author(models.Model):
name = models.CharField(max_length=200)
created_by = models.ForeignKey(User)
# ...
Create a custom :class:`ModelForm` in order to exclude the
``created_by`` field and prevent the user from editing it:
.. code-block:: python
# forms.py
from django import forms
from myapp.models import Author
class AuthorForm(forms.ModelForm):
class Meta:
model = Author
exclude = ('created_by',)
In the view, use the custom :attr:`form_class` and override
:meth:`form_valid()` to add the user::
# views.py
from django.views.generic.edit import CreateView
from myapp.models import Author
from myapp.forms import AuthorForm
class AuthorCreate(CreateView):
form_class = AuthorForm
model = Author
def form_valid(self, form):
form.instance.created_by = self.request.user
return super(AuthorCreate, self).form_valid(form)
Note that you'll need to :ref:`decorate this
view<decorating-class-based-views>` using
:func:`~django.contrib.auth.decorators.login_required`, or
alternatively handle unauthorised users in the :meth:`form_valid()`.

View File

@@ -0,0 +1,233 @@
=================
Class-based views
=================
.. versionadded:: 1.3
A view is a callable which takes a request and returns a
response. This can be more than just a function, and Django provides
an example of some classes which can be used as views. These allow you
to structure your views and reuse code by harnessing inheritance and
mixins. There are also some generic views for simple tasks which we'll
get to later, but you may want to design your own structure of
reusable views which suits your use case. For full details, see the
:doc:`class-based views reference
documentation</ref/class-based-views/index>`.
.. toctree::
:maxdepth: 1
generic-display
generic-editing
mixins
Basic examples
==============
Django provides base view classes which will suit a wide range of applications.
All views inherit from the :class:`~django.views.generic.base.View` class, which
handles linking the view in to the URLs, HTTP method dispatching and other
simple features. :class:`~django.views.generic.base.RedirectView` is for a simple HTTP
redirect, and :class:`~django.views.generic.base.TemplateView` extends the base class
to make it also render a template.
Simple usage
============
Class-based generic views (and any class-based views that inherit from
the base classes Django provides) can be configured in two
ways: subclassing, or passing in arguments directly in the URLconf.
When you subclass a class-based view, you can override attributes
(such as the ``template_name``) or methods (such as ``get_context_data``)
in your subclass to provide new values or methods. Consider, for example,
a view that just displays one template, ``about.html``. Django has a
generic view to do this - :class:`~django.views.generic.base.TemplateView` -
so we can just subclass it, and override the template name::
# some_app/views.py
from django.views.generic import TemplateView
class AboutView(TemplateView):
template_name = "about.html"
Then, we just need to add this new view into our URLconf. As the class-based
views themselves are classes, we point the URL to the ``as_view`` class method
instead, which is the entry point for class-based views::
# urls.py
from django.conf.urls import patterns, url, include
from some_app.views import AboutView
urlpatterns = patterns('',
(r'^about/', AboutView.as_view()),
)
Alternatively, if you're only changing a few simple attributes on a
class-based view, you can simply pass the new attributes into the ``as_view``
method call itself::
from django.conf.urls import patterns, url, include
from django.views.generic import TemplateView
urlpatterns = patterns('',
(r'^about/', TemplateView.as_view(template_name="about.html")),
)
A similar overriding pattern can be used for the ``url`` attribute on
:class:`~django.views.generic.base.RedirectView`.
.. _jsonresponsemixin-example:
More than just HTML
-------------------
Where class based views shine is when you want to do the same thing many times.
Suppose you're writing an API, and every view should return JSON instead of
rendered HTML.
We can create a mixin class to use in all of our views, handling the
conversion to JSON once.
For example, a simple JSON mixin might look something like this::
import json
from django.http import HttpResponse
class JSONResponseMixin(object):
"""
A mixin that can be used to render a JSON response.
"""
response_class = HttpResponse
def render_to_response(self, context, **response_kwargs):
"""
Returns a JSON response, transforming 'context' to make the payload.
"""
response_kwargs['content_type'] = 'application/json'
return self.response_class(
self.convert_context_to_json(context),
**response_kwargs
)
def convert_context_to_json(self, context):
"Convert the context dictionary into a JSON object"
# Note: This is *EXTREMELY* naive; in reality, you'll need
# to do much more complex handling to ensure that arbitrary
# objects -- such as Django model instances or querysets
# -- can be serialized as JSON.
return json.dumps(context)
Now we mix this into the base TemplateView::
from django.views.generic import TemplateView
class JSONView(JSONResponseMixin, TemplateView):
pass
Equally we could use our mixin with one of the generic views. We can make our
own version of :class:`~django.views.generic.detail.DetailView` by mixing
:class:`JSONResponseMixin` with the
:class:`~django.views.generic.detail.BaseDetailView` -- (the
:class:`~django.views.generic.detail.DetailView` before template
rendering behavior has been mixed in)::
class JSONDetailView(JSONResponseMixin, BaseDetailView):
pass
This view can then be deployed in the same way as any other
:class:`~django.views.generic.detail.DetailView`, with exactly the
same behavior -- except for the format of the response.
If you want to be really adventurous, you could even mix a
:class:`~django.views.generic.detail.DetailView` subclass that is able
to return *both* HTML and JSON content, depending on some property of
the HTTP request, such as a query argument or a HTTP header. Just mix
in both the :class:`JSONResponseMixin` and a
:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`,
and override the implementation of :func:`render_to_response()` to defer
to the appropriate subclass depending on the type of response that the user
requested::
class HybridDetailView(JSONResponseMixin, SingleObjectTemplateResponseMixin, BaseDetailView):
def render_to_response(self, context):
# Look for a 'format=json' GET argument
if self.request.GET.get('format','html') == 'json':
return JSONResponseMixin.render_to_response(self, context)
else:
return SingleObjectTemplateResponseMixin.render_to_response(self, context)
Because of the way that Python resolves method overloading, the local
``render_to_response()`` implementation will override the versions provided by
:class:`JSONResponseMixin` and
:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`.
For more information on how to use the built in generic views, consult the next
topic on :doc:`generic class based views</topics/class-based-views/generic-display>`.
Decorating class-based views
============================
.. highlightlang:: python
The extension of class-based views isn't limited to using mixins. You
can use also use decorators.
Decorating in URLconf
---------------------
The simplest way of decorating class-based views is to decorate the
result of the :meth:`~django.views.generic.base.View.as_view` method.
The easiest place to do this is in the URLconf where you deploy your
view::
from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView
from .views import VoteView
urlpatterns = patterns('',
(r'^about/', login_required(TemplateView.as_view(template_name="secret.html"))),
(r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),
)
This approach applies the decorator on a per-instance basis. If you
want every instance of a view to be decorated, you need to take a
different approach.
.. _decorating-class-based-views:
Decorating the class
--------------------
To decorate every instance of a class-based view, you need to decorate
the class definition itself. To do this you apply the decorator to the
:meth:`~django.views.generic.base.View.dispatch` method of the class.
A method on a class isn't quite the same as a standalone function, so
you can't just apply a function decorator to the method -- you need to
transform it into a method decorator first. The ``method_decorator``
decorator transforms a function decorator into a method decorator so
that it can be used on an instance method. For example::
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView
class ProtectedView(TemplateView):
template_name = 'secret.html'
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(ProtectedView, self).dispatch(*args, **kwargs)
In this example, every instance of ``ProtectedView`` will have
login protection.
.. note::
``method_decorator`` passes ``*args`` and ``**kwargs``
as parameters to the decorated method on the class. If your method
does not accept a compatible set of parameters it will raise a
``TypeError`` exception.

View File

@@ -0,0 +1,605 @@
===================================
Using mixins with class-based views
===================================
.. versionadded:: 1.3
.. caution::
This is an advanced topic. A working knowledge of :doc:`Django's
class-based views<index>` is advised before exploring these
techniques.
Django's built-in class-based views provide a lot of functionality,
but some of it you may want to use separately. For instance, you may
want to write a view that renders a template to make the HTTP
response, but you can't use
:class:`~django.views.generic.base.TemplateView`; perhaps you need to
render a template only on `POST`, with `GET` doing something else
entirely. While you could use
:class:`~django.template.response.TemplateResponse` directly, this
will likely result in duplicate code.
For this reason, Django also provides a number of mixins that provide
more discrete functionality. Template rendering, for instance, is
encapsulated in the
:class:`~django.views.generic.base.TemplateResponseMixin`. The Django
reference documentation contains :doc:`full documentation of all the
mixins</ref/class-based-views/mixins>`.
Context and template responses
==============================
Two central mixins are provided that help in providing a consistent
interface to working with templates in class-based views.
:class:`~django.views.generic.base.TemplateResponseMixin`
Every built in view which returns a
:class:`~django.template.response.TemplateResponse` will call the
:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`
method that :class:`TemplateResponseMixin` provides. Most of the time this
will be called for you (for instance, it is called by the ``get()`` method
implemented by both :class:`~django.views.generic.base.TemplateView` and
:class:`~django.views.generic.base.DetailView`); similarly, it's unlikely
that you'll need to override it, although if you want your response to
return something not rendered via a Django template then you'll want to do
it. For an example of this, see the :ref:`JSONResponseMixin example
<jsonresponsemixin-example>`.
``render_to_response`` itself calls
:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`,
which by default will just look up
:attr:`~django.views.generic.base.TemplateResponseMixin.template_name` on
the class-based view; two other mixins
(:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`
and
:class:`~django.views.generic.list.MultipleObjectTemplateResponseMixin`)
override this to provide more flexible defaults when dealing with actual
objects.
.. versionadded:: 1.5
:class:`~django.views.generic.base.ContextMixin`
Every built in view which needs context data, such as for rendering a
template (including :class:`TemplateResponseMixin` above), should call
:meth:`~django.views.generic.base.ContextMixin.get_context_data` passing
any data they want to ensure is in there as keyword arguments.
``get_context_data`` returns a dictionary; in :class:`ContextMixin` it
simply returns its keyword arguments, but it is common to override this to
add more members to the dictionary.
Building up Django's generic class-based views
===============================================
Let's look at how two of Django's generic class-based views are built
out of mixins providing discrete functionality. We'll consider
:class:`~django.views.generic.detail.DetailView`, which renders a
"detail" view of an object, and
:class:`~django.views.generic.list.ListView`, which will render a list
of objects, typically from a queryset, and optionally paginate
them. This will introduce us to four mixins which between them provide
useful functionality when working with either a single Django object,
or multiple objects.
There are also mixins involved in the generic edit views
(:class:`~django.views.generic.edit.FormView`, and the model-specific
views :class:`~django.views.generic.edit.CreateView`,
:class:`~django.views.generic.edit.UpdateView` and
:class:`~django.views.generic.edit.DeleteView`), and in the
date-based generic views. These are
covered in the :doc:`mixin reference
documentation</ref/class-based-views/mixins>`.
DetailView: working with a single Django object
-----------------------------------------------
To show the detail of an object, we basically need to do two things:
we need to look up the object and then we need to make a
:class:`TemplateResponse` with a suitable template, and that object as
context.
To get the object, :class:`~django.views.generic.detail.DetailView`
relies on :class:`~django.views.generic.detail.SingleObjectMixin`,
which provides a
:meth:`~django.views.generic.detail.SingleObjectMixin.get_object`
method that figures out the object based on the URL of the request (it
looks for ``pk`` and ``slug`` keyword arguments as declared in the
URLConf, and looks the object up either from the
:attr:`~django.views.generic.detail.SingleObjectMixin.model` attribute
on the view, or the
:attr:`~django.views.generic.detail.SingleObjectMixin.queryset`
attribute if that's provided). :class:`SingleObjectMixin` also overrides
:meth:`~django.views.generic.base.ContextMixin.get_context_data`,
which is used across all Django's built in class-based views to supply
context data for template renders.
To then make a :class:`TemplateResponse`, :class:`DetailView` uses
:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`,
which extends
:class:`~django.views.generic.base.TemplateResponseMixin`, overriding
:meth:`get_template_names()` as discussed above. It actually provides
a fairly sophisticated set of options, but the main one that most
people are going to use is
``<app_label>/<object_name>_detail.html``. The ``_detail`` part can be
changed by setting
:attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
on a subclass to something else. (For instance, the :doc:`generic edit
views<generic-editing>` use ``_form`` for create and update views, and
``_confirm_delete`` for delete views.)
ListView: working with many Django objects
------------------------------------------
Lists of objects follow roughly the same pattern: we need a (possibly
paginated) list of objects, typically a :class:`QuerySet`, and then we need
to make a :class:`TemplateResponse` with a suitable template using
that list of objects.
To get the objects, :class:`~django.views.generic.list.ListView` uses
:class:`~django.views.generic.list.MultipleObjectMixin`, which
provides both
:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`
and
:meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`. Unlike
with :class:`SingleObjectMixin`, there's no need to key off parts of
the URL to figure out the queryset to work with, so the default just
uses the
:attr:`~django.views.generic.list.MultipleObjectMixin.queryset` or
:attr:`~django.views.generic.list.MultipleObjectMixin.model` attribute
on the view class. A common reason to override
:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`
here would be to dynamically vary the objects, such as depending on
the current user or to exclude posts in the future for a blog.
:class:`MultipleObjectMixin` also overrides
:meth:`~django.views.generic.base.ContextMixin.get_context_data` to
include appropriate context variables for pagination (providing
dummies if pagination is disabled). It relies on ``object_list`` being
passed in as a keyword argument, which :class:`ListView` arranges for
it.
To make a :class:`TemplateResponse`, :class:`ListView` then uses
:class:`~django.views.generic.list.MultipleObjectTemplateResponseMixin`;
as with :class:`SingleObjectTemplateResponseMixin` above, this
overrides :meth:`get_template_names()` to provide :meth:`a range of
options
<~django.views.generic.list.MultipleObjectTempalteResponseMixin>`,
with the most commonly-used being
``<app_label>/<object_name>_list.html``, with the ``_list`` part again
being taken from the
:attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
attribute. (The date based generic views use suffixes such as ``_archive``,
``_archive_year`` and so on to use different templates for the various
specialised date-based list views.)
Using Django's class-based view mixins
======================================
Now we've seen how Django's generic class-based views use the provided
mixins, let's look at other ways we can combine them. Of course we're
still going to be combining them with either built-in class-based
views, or other generic class-based views, but there are a range of
rarer problems you can solve than are provided for by Django out of
the box.
.. warning::
Not all mixins can be used together, and not all generic class
based views can be used with all other mixins. Here we present a
few examples that do work; if you want to bring together other
functionality then you'll have to consider interactions between
attributes and methods that overlap between the different classes
you're using, and how `method resolution order`_ will affect which
versions of the methods will be called in what order.
The reference documentation for Django's :doc:`class-based
views</ref/class-based-views/index>` and :doc:`class-based view
mixins</ref/class-based-views/mixins>` will help you in
understanding which attributes and methods are likely to cause
conflict between different classes and mixins.
If in doubt, it's often better to back off and base your work on
:class:`View` or :class:`TemplateView`, perhaps with
:class:`SimpleObjectMixin` and
:class:`MultipleObjectMixin`. Although you will probably end up
writing more code, it is more likely to be clearly understandable
to someone else coming to it later, and with fewer interactions to
worry about you will save yourself some thinking. (Of course, you
can always dip into Django's implementation of the generic class
based views for inspiration on how to tackle problems.)
.. _method resolution order: http://www.python.org/download/releases/2.3/mro/
Using SingleObjectMixin with View
---------------------------------
If we want to write a simple class-based view that responds only to
``POST``, we'll subclass :class:`~django.views.generic.base.View` and
write a ``post()`` method in the subclass. However if we want our
processing to work on a particular object, identified from the URL,
we'll want the functionality provided by
:class:`~django.views.generic.detail.SingleObjectMixin`.
We'll demonstrate this with the publisher modelling we used in the
:doc:`generic class-based views
introduction<generic-display>`.
.. code-block:: python
# views.py
from django.http import HttpResponseForbidden, HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.views.generic import View
from django.views.generic.detail import SingleObjectMixin
from books.models import Author
class RecordInterest(View, SingleObjectMixin):
"""Records the current user's interest in an author."""
model = Author
def post(self, request, *args, **kwargs):
if not request.user.is_authenticated():
return HttpResponseForbidden()
# Look up the author we're interested in.
self.object = self.get_object()
# Actually record interest somehow here!
return HttpResponseRedirect(reverse('author-detail', kwargs={'pk': self.object.pk}))
In practice you'd probably want to record the interest in a key-value
store rather than in a relational database, so we've left that bit
out. The only bit of the view that needs to worry about using
:class:`SingleObjectMixin` is where we want to look up the author
we're interested in, which it just does with a simple call to
``self.get_object()``. Everything else is taken care of for us by the
mixin.
We can hook this into our URLs easily enough:
.. code-block:: python
# urls.py
from books.views import RecordInterest
urlpatterns = patterns('',
#...
url(r'^author/(?P<pk>\d+)/interest/$', RecordInterest.as_view(), name='author-interest'),
)
Note the ``pk`` named group, which
:meth:`~django.views.generic.detail.SingleObjectMixin.get_object` uses
to look up the :class:`Author` instance. You could also use a slug, or
any of the other features of :class:`SingleObjectMixin`.
Using SingleObjectMixin with ListView
-------------------------------------
:class:`~django.views.generic.list.ListView` provides built-in
pagination, but you might want to paginate a list of objects that are
all linked (by a foreign key) to another object. In our publishing
example, you might want to paginate through all the books by a
particular publisher.
One way to do this is to combine :class:`ListView` with
:class:`SingleObjectMixin`, so that the queryset for the paginated
list of books can hang off the publisher found as the single
object. In order to do this, we need to have two different querysets:
**Publisher queryset for use in get_object**
We'll set that up directly when we call :meth:`get_object()`.
**Book queryset for use by ListView**
We'll figure that out ourselves in :meth:`get_queryset()` so we
can take into account the Publisher we're looking at.
.. highlightlang:: python
.. note::
We have to think carefully about :meth:`get_context_data()`.
Since both :class:`SingleObjectMixin` and :class:`ListView` will
put things in the context data under the value of
:attr:`context_object_name` if it's set, we'll instead explictly
ensure the Publisher is in the context data. :class:`ListView`
will add in the suitable ``page_obj`` and ``paginator`` for us
providing we remember to call ``super()``.
Now we can write a new :class:`PublisherDetail`::
from django.views.generic import ListView
from django.views.generic.detail import SingleObjectMixin
from books.models import Publisher
class PublisherDetail(SingleObjectMixin, ListView):
paginate_by = 2
template_name = "books/publisher_detail.html"
def get_context_data(self, **kwargs):
kwargs['publisher'] = self.object
return super(PublisherDetail, self).get_context_data(**kwargs)
def get_queryset(self):
self.object = self.get_object(Publisher.objects.all())
return self.object.book_set.all()
Notice how we set ``self.object`` within :meth:`get_queryset` so we
can use it again later in :meth:`get_context_data`. If you don't set
:attr:`template_name`, the template will default to the normal
:class:`ListView` choice, which in this case would be
``"books/book_list.html"`` because it's a list of books;
:class:`ListView` knows nothing about :class:`SingleObjectMixin`, so
it doesn't have any clue this view is anything to do with a Publisher.
.. highlightlang:: html+django
The ``paginate_by`` is deliberately small in the example so you don't
have to create lots of books to see the pagination working! Here's the
template you'd want to use::
{% extends "base.html" %}
{% block content %}
<h2>Publisher {{ publisher.name }}</h2>
<ol>
{% for book in page_obj %}
<li>{{ book.title }}</li>
{% endfor %}
</ol>
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">next</a>
{% endif %}
</span>
</div>
{% endblock %}
Avoid anything more complex
===========================
Generally you can use
:class:`~django.views.generic.base.TemplateResponseMixin` and
:class:`~django.views.generic.detail.SingleObjectMixin` when you need
their functionality. As shown above, with a bit of care you can even
combine :class:`SingleObjectMixin` with
:class:`~django.views.generic.list.ListView`. However things get
increasingly complex as you try to do so, and a good rule of thumb is:
.. hint::
Each of your views should use only mixins or views from one of the
groups of generic class-based views: :doc:`detail,
list<generic-display>`, :doc:`editing<generic-editing>` and
date. For example it's fine to combine
:class:`TemplateView` (built in view) with
:class:`MultipleObjectMixin` (generic list), but you're likely to
have problems combining :class:`SingleObjectMixin` (generic
detail) with :class:`MultipleObjectMixin` (generic list).
To show what happens when you try to get more sophisticated, we show
an example that sacrifices readability and maintainability when there
is a simpler solution. First, let's look at a naive attempt to combine
:class:`~django.views.generic.detail.DetailView` with
:class:`~django.views.generic.edit.FormMixin` to enable use to
``POST`` a Django :class:`Form` to the same URL as we're displaying an
object using :class:`DetailView`.
Using FormMixin with DetailView
-------------------------------
Think back to our earlier example of using :class:`View` and
:class:`SingleObjectMixin` together. We were recording a user's
interest in a particular author; say now that we want to let them
leave a message saying why they like them. Again, let's assume we're
not going to store this in a relational database but instead in
something more esoteric that we won't worry about here.
At this point it's natural to reach for a :class:`Form` to encapsulate
the information sent from the user's browser to Django. Say also that
we're heavily invested in `REST`_, so we want to use the same URL for
displaying the author as for capturing the message from the
user. Let's rewrite our :class:`AuthorDetailView` to do that.
.. _REST: http://en.wikipedia.org/wiki/Representational_state_transfer
We'll keep the ``GET`` handling from :class:`DetailView`, although
we'll have to add a :class:`Form` into the context data so we can
render it in the template. We'll also want to pull in form processing
from :class:`~django.views.generic.edit.FormMixin`, and write a bit of
code so that on ``POST`` the form gets called appropriately.
.. note::
We use :class:`FormMixin` and implement :meth:`post()` ourselves
rather than try to mix :class:`DetailView` with :class:`FormView`
(which provides a suitable :meth:`post()` already) because both of
the views implement :meth:`get()`, and things would get much more
confusing.
Our new :class:`AuthorDetail` looks like this:
.. code-block:: python
# CAUTION: you almost certainly do not want to do this.
# It is provided as part of a discussion of problems you can
# run into when combining different generic class-based view
# functionality that is not designed to be used together.
from django import forms
from django.http import HttpResponseForbidden
from django.core.urlresolvers import reverse
from django.views.generic import DetailView
from django.views.generic.edit import FormMixin
class AuthorInterestForm(forms.Form):
message = forms.CharField()
class AuthorDetail(DetailView, FormMixin):
model = Author
form_class = AuthorInterestForm
def get_success_url(self):
return reverse(
'author-detail',
kwargs = {'pk': self.object.pk},
)
def get_context_data(self, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
context = {
'form': form
}
context.update(kwargs)
return super(AuthorDetail, self).get_context_data(**context)
def post(self, request, *args, **kwargs):
form_class = self.get_form_class()
form = self.get_form(form_class)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
if not self.request.user.is_authenticated():
return HttpResponseForbidden()
self.object = self.get_object()
# record the interest using the message in form.cleaned_data
return super(AuthorDetail, self).form_valid(form)
:meth:`get_success_url()` is just providing somewhere to redirect to,
which gets used in the default implementation of
:meth:`form_valid()`. We have to provide our own :meth:`post()` as
noted earlier, and override :meth:`get_context_data()` to make the
:class:`Form` available in the context data.
A better solution
-----------------
It should be obvious that the number of subtle interactions between
:class:`FormMixin` and :class:`DetailView` is already testing our
ability to manage things. It's unlikely you'd want to write this kind
of class yourself.
In this case, it would be fairly easy to just write the :meth:`post()`
method yourself, keeping :class:`DetailView` as the only generic
functionality, although writing :class:`Form` handling code involves a
lot of duplication.
Alternatively, it would still be easier than the above approach to
have a separate view for processing the form, which could use
:class:`~django.views.generic.edit.FormView` distinct from
:class:`DetailView` without concerns.
An alternative better solution
------------------------------
What we're really trying to do here is to use two different class
based views from the same URL. So why not do just that? We have a very
clear division here: ``GET`` requests should get the
:class:`DetailView` (with the :class:`Form` added to the context
data), and ``POST`` requests should get the :class:`FormView`. Let's
set up those views first.
The :class:`AuthorDisplay` view is almost the same as :ref:`when we
first introduced AuthorDetail<generic-views-extra-work>`; we have to
write our own :meth:`get_context_data()` to make the
:class:`AuthorInterestForm` available to the template. We'll skip the
:meth:`get_object()` override from before for clarity.
.. code-block:: python
from django.views.generic import DetailView
from django import forms
from books.models import Author
class AuthorInterestForm(forms.Form):
message = forms.CharField()
class AuthorDisplay(DetailView):
queryset = Author.objects.all()
def get_context_data(self, **kwargs):
context = {
'form': AuthorInterestForm(),
}
context.update(kwargs)
return super(AuthorDisplay, self).get_context_data(**context)
Then the :class:`AuthorInterest` is a simple :class:`FormView`, but we
have to bring in :class:`SingleObjectMixin` so we can find the author
we're talking about, and we have to remember to set
:attr:`template_name` to ensure that form errors will render the same
template as :class:`AuthorDisplay` is using on ``GET``.
.. code-block:: python
from django.views.generic import FormView
from django.views.generic.detail import SingleObjectMixin
class AuthorInterest(FormView, SingleObjectMixin):
template_name = 'books/author_detail.html'
form_class = AuthorInterestForm
model = Author
def get_context_data(self, **kwargs):
context = {
'object': self.get_object(),
}
return super(AuthorInterest, self).get_context_data(**context)
def get_success_url(self):
return reverse(
'author-detail',
kwargs = {'pk': self.object.pk},
)
def form_valid(self, form):
if not self.request.user.is_authenticated():
return HttpResponseForbidden()
self.object = self.get_object()
# record the interest using the message in form.cleaned_data
return super(AuthorInterest, self).form_valid(form)
Finally we bring this together in a new :class:`AuthorDetail` view. We
already know that calling :meth:`as_view()` on a class-based view
gives us something that behaves exactly like a function based view, so
we can do that at the point we choose between the two subviews.
You can of course pass through keyword arguments to :meth:`as_view()`
in the same way you would in your URLconf, such as if you wanted the
:class:`AuthorInterest` behaviour to also appear at another URL but
using a different template.
.. code-block:: python
from django.views.generic import View
class AuthorDetail(View):
def get(self, request, *args, **kwargs):
view = AuthorDisplay.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
view = AuthorInterest.as_view()
return view(request, *args, **kwargs)
This approach can also be used with any other generic class-based
views or your own class-based views inheriting directly from
:class:`View` or :class:`TemplateView`, as it keeps the different
views as separate as possible.

View File

@@ -156,11 +156,11 @@ ones:
A choices list looks like this::
YEAR_IN_SCHOOL_CHOICES = (
(u'FR', u'Freshman'),
(u'SO', u'Sophomore'),
(u'JR', u'Junior'),
(u'SR', u'Senior'),
(u'GR', u'Graduate'),
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
)
The first element in each tuple is the value that will be stored in the
@@ -172,21 +172,22 @@ ones:
from django.db import models
class Person(models.Model):
GENDER_CHOICES = (
(u'M', u'Male'),
(u'F', u'Female'),
SHIRT_SIZES = (
('S', 'Small'),
('M', 'Medium'),
('L', 'Large'),
)
name = models.CharField(max_length=60)
gender = models.CharField(max_length=2, choices=GENDER_CHOICES)
shirt_size = models.CharField(max_length=2, choices=SHIRT_SIZES)
::
>>> p = Person(name="Fred Flintstone", gender="M")
>>> p = Person(name="Fred Flintstone", shirt_size="L")
>>> p.save()
>>> p.gender
u'M'
>>> p.get_gender_display()
u'Male'
>>> p.shirt_size
u'L'
>>> p.get_shirt_size_display()
u'Large'
:attr:`~Field.default`
The default value for the field. This can be a value or a callable
@@ -383,7 +384,8 @@ Extra fields on many-to-many relationships
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When you're only dealing with simple many-to-many relationships such as
mixing and matching pizzas and toppings, a standard :class:`~django.db.models.ManyToManyField` is all you need. However, sometimes
mixing and matching pizzas and toppings, a standard
:class:`~django.db.models.ManyToManyField` is all you need. However, sometimes
you may need to associate data with the relationship between two models.
For example, consider the case of an application tracking the musical groups
@@ -880,8 +882,6 @@ field. This would normally cause a problem in abstract base classes, since the
fields on this class are included into each of the child classes, with exactly
the same values for the attributes (including :attr:`~django.db.models.ForeignKey.related_name`) each time.
.. versionchanged:: 1.2
To work around this problem, when you are using :attr:`~django.db.models.ForeignKey.related_name` in an
abstract base class (only), part of the name should contain
``'%(app_label)s'`` and ``'%(class)s'``.

View File

@@ -2,8 +2,6 @@
Multiple databases
==================
.. versionadded:: 1.2
This topic guide describes Django's support for interacting with
multiple databases. Most of the rest of Django's documentation assumes
you are interacting with a single database. If you want to interact

View File

@@ -230,7 +230,7 @@ It is optimal because:
#. Use of :ttag:`with` means that we store ``user.emails.all`` in a variable
for later use, allowing its cache to be re-used.
#. The line ``{% if emails %}`` causes ``QuerySet.__nonzero__()`` to be called,
#. The line ``{% if emails %}`` causes ``QuerySet.__bool__()`` to be called,
which causes the ``user.emails.all()`` query to be run on the database, and
at the least the first line to be turned into an ORM object. If there aren't
any results, it will return False, otherwise True.

View File

@@ -18,8 +18,6 @@ __ `executing custom SQL directly`_
Performing raw queries
======================
.. versionadded:: 1.2
The ``raw()`` manager method can be used to perform raw SQL queries that
return model instances:

View File

@@ -54,6 +54,13 @@ The various cache middlewares are an exception:
Even when using database caching, Django's cache backend uses its own
database cursor (which is mapped to its own database connection internally).
.. note::
The ``TransactionMiddleware`` only affects the database aliased
as "default" within your :setting:`DATABASES` setting. If you are using
multiple databases and want transaction control over databases other than
"default", you will need to write your own transaction middleware.
.. _transaction-management-functions:
Controlling transaction management in views

View File

@@ -192,7 +192,7 @@ from the request's POST data, sends that to admin@example.com and redirects to
# to get proper validation errors.
return HttpResponse('Make sure all fields are entered and valid.')
.. _Header injection: http://www.nyphp.org/phundamentals/email_header_injection.php
.. _Header injection: http://www.nyphp.org/phundamentals/8_Preventing-Email-Header-Injection
.. _emailmessage-and-smtpconnection:
@@ -365,8 +365,6 @@ subtype. For example::
Email backends
==============
.. versionadded:: 1.2
The actual sending of an email is handled by the email backend.
The email backend class has the following methods:

View File

@@ -75,6 +75,29 @@ using a Python built-in ``file`` object::
Now you can use any of the documented attributes and methods
of the :class:`~django.core.files.File` class.
Be aware that files created in this way are not automatically closed.
The following approach may be used to close files automatically::
>>> from django.core.files import File
# Create a Python file object using open() and the with statement
>>> with open('/tmp/hello.world', 'w') as f:
>>> myfile = File(f)
>>> for line in myfile:
>>> print line
>>> myfile.closed
True
>>> f.closed
True
Closing files is especially important when accessing file fields in a loop
over a large number of objects:: If files are not manually closed after
accessing them, the risk of running out of file descriptors may arise. This
may lead to the following error:
IOError: [Errno 24] Too many open files
File storage
============

View File

@@ -102,15 +102,12 @@ limit the maximum number of empty forms the formset will display::
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
.. versionchanged:: 1.2
If the value of ``max_num`` is greater than the number of existing
objects, up to ``extra`` additional blank forms will be added to the formset,
so long as the total number of forms does not exceed ``max_num``.
A ``max_num`` value of ``None`` (the default) puts no limit on the number of
forms displayed. Please note that the default value of ``max_num`` was changed
from ``0`` to ``None`` in version 1.2 to allow ``0`` as a valid value.
forms displayed.
Formset validation
------------------
@@ -210,8 +207,6 @@ pre-filled, and is also used to determine how many forms are required. You
will probably never need to override either of these methods, so please be
sure you understand what they do before doing so.
.. versionadded:: 1.2
``empty_form``
~~~~~~~~~~~~~~

View File

@@ -82,6 +82,8 @@ If your form is going to be used to directly add or edit a Django model, you can
use a :doc:`ModelForm </topics/forms/modelforms>` to avoid duplicating your model
description.
.. _using-a-form-in-a-view:
Using a form in a view
----------------------
@@ -89,6 +91,9 @@ The standard pattern for processing a form in a view looks like this:
.. code-block:: python
from django.shortcuts import render
from django.http import HttpResponseRedirect
def contact(request):
if request.method == 'POST': # If the form has been submitted...
form = ContactForm(request.POST) # A form bound to the POST data
@@ -99,53 +104,63 @@ The standard pattern for processing a form in a view looks like this:
else:
form = ContactForm() # An unbound form
return render_to_response('contact.html', {
return render(request, 'contact.html', {
'form': form,
})
There are three code paths here:
There are three possible code paths here:
1. If the form has not been submitted, an unbound instance of ContactForm is
created and passed to the template.
2. If the form has been submitted, a bound instance of the form is created
using ``request.POST``. If the submitted data is valid, it is processed
and the user is re-directed to a "thanks" page.
3. If the form has been submitted but is invalid, the bound form instance is
passed on to the template.
+------------------+---------------+-----------------------------------------+
| Form submitted? | Data? | What occurs |
+==================+===============+=========================================+
| Unsubmitted | None yet | Template gets passed unbound instance |
| | | of ContactForm. |
+------------------+---------------+-----------------------------------------+
| Submitted | Invalid data | Template gets passed bound instance |
| | | of ContactForm. |
+------------------+---------------+-----------------------------------------+
| Submitted | Valid data | Valid data is processed. Redirect to a |
| | | "thanks" page. |
+------------------+---------------+-----------------------------------------+
The distinction between **bound** and **unbound** forms is important. An unbound
form does not have any data associated with it; when rendered to the user, it
will be empty or will contain default values. A bound form does have submitted
data, and hence can be used to tell if that data is valid. If an invalid bound
form is rendered it can include inline error messages telling the user where
they went wrong.
The distinction between :ref:`ref-forms-api-bound-unbound` is important:
See :ref:`ref-forms-api-bound-unbound` for further information on the
differences between bound and unbound forms.
* An unbound form has no data associated with it. When rendered to the user,
it will be empty or will contain default values.
* A bound form has submitted data, and hence can be used to tell if that data
is valid. If an invalid bound form is rendered, it can include inline error
messages telling the user what data to correct.
Handling file uploads with a form
---------------------------------
To see how to handle file uploads with your form see
:ref:`binding-uploaded-files` for more information.
To see how to handle file uploads with your form, see
:ref:`binding-uploaded-files`.
Processing the data from a form
-------------------------------
Once ``is_valid()`` returns ``True``, you can process the form submission safe
in the knowledge that it conforms to the validation rules defined by your form.
While you could access ``request.POST`` directly at this point, it is better to
access ``form.cleaned_data``. This data has not only been validated but will
also be converted in to the relevant Python types for you. In the above example,
``cc_myself`` will be a boolean value. Likewise, fields such as ``IntegerField``
and ``FloatField`` convert values to a Python int and float respectively. Note
that read-only fields are not available in ``form.cleaned_data`` (and setting
a value in a custom ``clean()`` method won't have any effect) because these
Once ``is_valid()`` returns ``True``, the successfully validated form data
will be in the ``form.cleaned_data`` dictionary. This data will have been
converted nicely into Python types for you.
.. note::
You can still access the unvalidated data directly from ``request.POST`` at
this point, but the validated data is better.
In the above example, ``cc_myself`` will be a boolean value. Likewise, fields
such as ``IntegerField`` and ``FloatField`` convert values to a Python int and
float respectively.
Read-only fields are not available in ``form.cleaned_data`` (and setting
a value in a custom ``clean()`` method won't have any effect). These
fields are displayed as text rather than as input elements, and thus are not
posted back to the server.
Extending the above example, here's how the form data could be processed:
Extending the earlier example, here's how the form data could be processed:
.. code-block:: python
@@ -163,7 +178,9 @@ Extending the above example, here's how the form data could be processed:
send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/') # Redirect after POST
For more on sending email from Django, see :doc:`/topics/email`.
.. tip::
For more on sending email from Django, see :doc:`/topics/email`.
Displaying a form using a template
----------------------------------
@@ -294,7 +311,7 @@ templates:
The field's label wrapped in the appropriate HTML ``<label>`` tag,
e.g. ``<label for="id_email">Email address</label>``
``{{ field.value }}``
``{{ field.value }}``
The value of the field. e.g ``someone@example.com``
``{{ field.html_name }}``

View File

@@ -109,9 +109,6 @@ Model field Form field
``URLField`` ``URLField``
=============================== ========================================
.. versionadded:: 1.2
The ``BigIntegerField`` is new in Django 1.2.
As you might expect, the ``ForeignKey`` and ``ManyToManyField`` model field
types are special cases:
@@ -199,10 +196,11 @@ The ``is_valid()`` method and ``errors``
----------------------------------------
The first time you call ``is_valid()`` or access the ``errors`` attribute of a
``ModelForm`` triggers form validation as well as :ref:`model validation
<validating-objects>`. This has the side-effect of cleaning the model you pass
to the ``ModelForm`` constructor. For instance, calling ``is_valid()`` on your
form will convert any date fields on your model to actual date objects.
``ModelForm`` triggers :ref:`form validation <form-and-field-validation>` as
well as :ref:`model validation <validating-objects>`. This has the side-effect
of cleaning the model you pass to the ``ModelForm`` constructor. For instance,
calling ``is_valid()`` on your form will convert any date fields on your model
to actual date objects.
The ``save()`` method
@@ -362,9 +360,6 @@ Since the Author model has only 3 fields, 'name', 'title', and
Overriding the default field types or widgets
---------------------------------------------
.. versionadded:: 1.2
The ``widgets`` attribute is new in Django 1.2.
The default field types, as described in the `Field types`_ table above, are
sensible defaults. If you have a ``DateField`` in your model, chances are you'd
want that to be represented as a ``DateField`` in your form. But
@@ -442,6 +437,10 @@ parameter when declaring the form field::
class Meta:
model = Article
You must ensure that the type of the form field can be used to set the
contents of the corresponding model field. When they are not compatible,
you will get a ``ValueError`` as no implicit conversion takes place.
See the :doc:`form field documentation </ref/forms/fields>` for more information
on fields and their arguments.
@@ -670,8 +669,6 @@ are saved properly.
Limiting the number of editable objects
---------------------------------------
.. versionchanged:: 1.2
As with regular formsets, you can use the ``max_num`` and ``extra`` parameters
to ``modelformset_factory`` to limit the number of extra forms displayed.
@@ -698,8 +695,6 @@ so long as the total number of forms does not exceed ``max_num``::
<tr><th><label for="id_form-2-name">Name:</label></th><td><input id="id_form-2-name" type="text" name="form-2-name" value="Walt Whitman" maxlength="100" /><input type="hidden" name="form-2-id" value="2" id="id_form-2-id" /></td></tr>
<tr><th><label for="id_form-3-name">Name:</label></th><td><input id="id_form-3-name" type="text" name="form-3-name" maxlength="100" /><input type="hidden" name="form-3-id" id="id_form-3-id" /></td></tr>
.. versionchanged:: 1.2
A ``max_num`` value of ``None`` (the default) puts no limit on the number of
forms displayed.
@@ -886,7 +881,8 @@ of a model. Here's how you can do that::
formset = BookInlineFormSet(request.POST, request.FILES, instance=author)
if formset.is_valid():
formset.save()
# Do something.
# Do something. Should generally end with a redirect. For example:
return HttpResponseRedirect(author.get_absolute_url())
else:
formset = BookInlineFormSet(instance=author)
return render_to_response("manage_books.html", {

View File

@@ -178,6 +178,50 @@ Three settings control Django's file upload behavior:
Which means "try to upload to memory first, then fall back to temporary
files."
Handling uploaded files with a model
------------------------------------
If you're saving a file on a :class:`~django.db.models.Model` with a
:class:`~django.db.models.FileField`, using a :class:`~django.forms.ModelForm`
makes this process much easier. The file object will be saved when calling
``form.save()``::
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import ModelFormWithFileField
def upload_file(request):
if request.method == 'POST':
form = ModelFormWithFileField(request.POST, request.FILES)
if form.is_valid():
# file is saved
form.save()
return HttpResponseRedirect('/success/url/')
else:
form = ModelFormWithFileField()
return render('upload.html', {'form': form})
If you are constructing an object manually, you can simply assign the file
object from :attr:`request.FILES <django.http.HttpRequest.FILES>` to the file
field in the model::
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import UploadFileForm
from .models import ModelWithFileField
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
instance = ModelWithFileField(file_field=request.FILES['file'])
instance.save()
return HttpResponseRedirect('/success/url/')
else:
form = UploadFileForm()
return render('upload.html', {'form': form})
``UploadedFile`` objects
========================

View File

@@ -2,4 +2,4 @@
Generic views
=============
See :doc:`/ref/class-based-views`.
See :doc:`/ref/class-based-views/index`.

View File

@@ -199,7 +199,8 @@ of caveats:
define ``__init__`` as requiring any arguments.
* Unlike the ``process_*`` methods which get called once per request,
``__init__`` gets called only *once*, when the Web server starts up.
``__init__`` gets called only *once*, when the Web server responds to the
first request.
Marking middleware as unused
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -423,6 +423,9 @@ cookie will be sent on every request.
Similarly, the ``expires`` part of a session cookie is updated each time the
session cookie is sent.
.. versionchanged:: 1.5
The session is not saved if the response's status code is 500.
Browser-length sessions vs. persistent sessions
===============================================
@@ -503,7 +506,7 @@ SESSION_COOKIE_DOMAIN
Default: ``None``
The domain to use for session cookies. Set this to a string such as
``".lawrence.com"`` (note the leading dot!) for cross-domain cookies, or use
``".example.com"`` (note the leading dot!) for cross-domain cookies, or use
``None`` for a standard domain cookie.
SESSION_COOKIE_HTTPONLY
@@ -521,7 +524,7 @@ consistently by all browsers. However, when it is honored, it can be a
useful way to mitigate the risk of client side script accessing the
protected cookie data.
.. _HTTPOnly: http://www.owasp.org/index.php/HTTPOnly
.. _HTTPOnly: https://www.owasp.org/index.php/HTTPOnly
SESSION_COOKIE_NAME
-------------------

View File

@@ -15,7 +15,7 @@ introduce controlled coupling for convenience's sake.
``render``
==========
.. function:: render(request, template[, dictionary][, context_instance][, content_type][, status][, current_app])
.. function:: render(request, template_name[, dictionary][, context_instance][, content_type][, status][, current_app])
.. versionadded:: 1.3
@@ -32,7 +32,7 @@ Required arguments
``request``
The request object used to generate this response.
``template``
``template_name``
The full name of a template to use or sequence of template names.
Optional arguments

View File

@@ -314,9 +314,6 @@ that should be called if none of the URL patterns match.
By default, this is ``'django.views.defaults.page_not_found'``. That default
value should suffice.
.. versionchanged:: 1.2
Previous versions of Django only accepted strings representing import paths.
handler500
----------
@@ -329,9 +326,6 @@ have runtime errors in view code.
By default, this is ``'django.views.defaults.server_error'``. That default
value should suffice.
.. versionchanged:: 1.2
Previous versions of Django only accepted strings representing import paths.
Notes on capturing text in URLs
===============================
@@ -710,8 +704,8 @@ target each pattern individually by using its name:
.. code-block:: html+django
{% url arch-summary 1945 %}
{% url full-archive 2007 %}
{% url 'arch-summary' 1945 %}
{% url 'full-archive' 2007 %}
Even though both URL patterns refer to the ``archive`` view here, using the
``name`` parameter to ``url()`` allows you to tell them apart in templates.

View File

@@ -4,8 +4,6 @@
Format localization
===================
.. versionadded:: 1.2
Overview
========
@@ -23,7 +21,10 @@ necessary to set :setting:`USE_L10N = True <USE_L10N>` in your settings file.
The default :file:`settings.py` file created by :djadmin:`django-admin.py
startproject <startproject>` includes :setting:`USE_L10N = True <USE_L10N>`
for convenience.
for convenience. Note, however, that to enable number formatting with
thousand separators it is necessary to set :setting:`USE_THOUSAND_SEPARATOR
= True <USE_THOUSAND_SEPARATOR>` in your settings file. Alternatively, you
could use :tfilter:`intcomma` to format numbers in your template.
.. note::

View File

@@ -509,7 +509,7 @@ Setup
Finally, our calendar system contains interesting traps for computers::
>>> import datetime
>>> def substract_one_year(value): # DON'T DO THAT!
>>> def one_year_before(value): # DON'T DO THAT!
... return value.replace(year=value.year - 1)
>>> one_year_before(datetime.datetime(2012, 3, 1, 10, 0))
datetime.datetime(2011, 3, 1, 10, 0)

View File

@@ -37,6 +37,13 @@ from your :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting.
controls if Django should implement format localization. See
:doc:`/topics/i18n/formatting` for more details.
.. note::
Make sure you've activated translation for your project (the fastest way is
to check if :setting:`MIDDLEWARE_CLASSES` includes
:mod:`django.middleware.locale.LocaleMiddleware`). If you haven't yet,
see :ref:`how-django-discovers-language-preference`.
Internationalization: in Python code
====================================
@@ -317,10 +324,10 @@ Model fields and relationships ``verbose_name`` and ``help_text`` option values
For example, to translate the help text of the *name* field in the following
model, do the following::
from django.utils.translation import ugettext_lazy
from django.utils.translation import ugettext_lazy as _
class MyThing(models.Model):
name = models.CharField(help_text=ugettext_lazy('This is the help text'))
name = models.CharField(help_text=_('This is the help text'))
You can mark names of ``ForeignKey``, ``ManyTomanyField`` or ``OneToOneField``
relationship as translatable by using their ``verbose_name`` options::
@@ -344,14 +351,14 @@ It is recommended to always provide explicit
relying on the fallback English-centric and somewhat naïve determination of
verbose names Django performs bu looking at the model's class name::
from django.utils.translation import ugettext_lazy
from django.utils.translation import ugettext_lazy as _
class MyThing(models.Model):
name = models.CharField(_('name'), help_text=ugettext_lazy('This is the help text'))
name = models.CharField(_('name'), help_text=_('This is the help text'))
class Meta:
verbose_name = ugettext_lazy('my thing')
verbose_name_plural = ugettext_lazy('my things')
verbose_name = _('my thing')
verbose_name_plural = _('my things')
Model methods ``short_description`` attribute values
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -416,8 +423,8 @@ result is included in a string. For example::
from django.utils.translation import string_concat
...
name = ugettext_lazy(u'John Lennon')
instrument = ugettext_lazy(u'guitar')
name = ugettext_lazy('John Lennon')
instrument = ugettext_lazy('guitar')
result = string_concat(name, ': ', instrument)
In this case, the lazy translations in ``result`` will only be converted to
@@ -456,6 +463,9 @@ Internationalization: in template code
Translations in :doc:`Django templates </topics/templates>` uses two template
tags and a slightly different syntax than in Python code. To give your template
access to these tags, put ``{% load i18n %}`` toward the top of your template.
As with all template tags, this tag needs to be loaded in all templates which
use translations, even those templates that extend from other templates which
have already loaded the ``i18n`` tag.
.. templatetag:: trans
@@ -596,7 +606,7 @@ apply.
Reverse URL lookups cannot be carried out within the ``blocktrans`` and should
be retrieved (and stored) beforehand::
{% url path.to.view arg arg2 as the_url %}
{% url 'path.to.view' arg arg2 as the_url %}
{% blocktrans %}
This is a URL: {{ the_url }}
{% endblocktrans %}
@@ -790,7 +800,7 @@ To use the catalog, just pull in the dynamically generated script like this:
.. code-block:: html+django
<script type="text/javascript" src="{% url django.views.i18n.javascript_catalog %}"></script>
<script type="text/javascript" src="{% url 'django.views.i18n.javascript_catalog' %}"></script>
This uses reverse URL lookup to find the URL of the JavaScript catalog view.
When the catalog is loaded, your JavaScript code can use the standard
@@ -890,7 +900,7 @@ prepend the current active language code to all url patterns defined within
urlpatterns += i18n_patterns('',
url(r'^about/$', 'about.view', name='about'),
url(r'^news/$', include(news_patterns, namespace='news')),
url(r'^news/', include(news_patterns, namespace='news')),
)
@@ -945,7 +955,7 @@ URL patterns can also be marked translatable using the
urlpatterns += i18n_patterns('',
url(_(r'^about/$'), 'about.view', name='about'),
url(_(r'^news/$'), include(news_patterns, namespace='news')),
url(_(r'^news/'), include(news_patterns, namespace='news')),
)
@@ -992,7 +1002,7 @@ template tag. It enables the given language in the enclosed template section:
{% trans "View this category in:" %}
{% for lang_code, lang_name in languages %}
{% language lang_code %}
<a href="{% url category slug=category.slug %}">{{ lang_name }}</a>
<a href="{% url 'category' slug=category.slug %}">{{ lang_name }}</a>
{% endlanguage %}
{% endfor %}
@@ -1039,8 +1049,6 @@ Django comes with a tool, :djadmin:`django-admin.py makemessages
commands from the GNU gettext toolset: ``xgettext``, ``msgfmt``,
``msgmerge`` and ``msguniq``.
.. versionchanged:: 1.2
The minimum version of the ``gettext`` utilities supported is 0.15.
To create or update a message file, run this command::
@@ -1249,6 +1257,12 @@ Activate this view by adding the following line to your URLconf::
(Note that this example makes the view available at ``/i18n/setlang/``.)
.. warning::
Make sure that you don't include the above URL within
:func:`~django.conf.urls.i18n.i18n_patterns` - it needs to be
language-independent itself to work correctly.
The view expects to be called via the ``POST`` method, with a ``language``
parameter set in request. If session support is enabled, the view
saves the language choice in the user's session. Otherwise, it saves the
@@ -1268,7 +1282,7 @@ Here's example HTML template code:
.. code-block:: html+django
<form action="/i18n/setlang/" method="post">
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language">

View File

@@ -11,7 +11,7 @@ Introductions to all the key parts of Django you'll need to know:
http/index
forms/index
templates
class-based-views
class-based-views/index
files
testing
auth
@@ -22,6 +22,7 @@ Introductions to all the key parts of Django you'll need to know:
i18n/index
logging
pagination
python3
security
serialization
settings

View File

@@ -9,7 +9,7 @@ Install Python
Being a Python Web framework, Django requires Python.
It works with any Python version from 2.6 to 2.7 (due to backwards
It works with any Python version from 2.6.5 to 2.7 (due to backwards
incompatibilities in Python 3.0, Django does not currently work with
Python 3.0; see :doc:`the Django FAQ </faq/install>` for more
information on supported Python versions and the 3.0 transition).
@@ -62,7 +62,7 @@ for information on how to configure mod_wsgi once you have it
installed.
If you can't use mod_wsgi for some reason, fear not: Django supports many other
deployment options. One is :doc:`uWSGI </howto/deployment/fastcgi>`; it works
deployment options. One is :doc:`uWSGI </howto/deployment/wsgi/uwsgi>`; it works
very well with `nginx`_. Another is :doc:`FastCGI </howto/deployment/fastcgi>`,
perfect for using Django with servers other than Apache. Additionally, Django
follows the WSGI spec (:pep:`3333`), which allows it to run on a variety of
@@ -70,7 +70,7 @@ server platforms. See the `server-arrangements wiki page`_ for specific
installation instructions for each platform.
.. _Apache: http://httpd.apache.org/
.. _nginx: http://nginx.net/
.. _nginx: http://nginx.org/
.. _mod_wsgi: http://code.google.com/p/modwsgi/
.. _server-arrangements wiki page: https://code.djangoproject.com/wiki/ServerArrangements
@@ -107,7 +107,7 @@ database bindings are installed.
If you're on Windows, check out the unofficial `compiled Windows version`_.
* If you're using MySQL, you'll need MySQLdb_, version 1.2.1p2 or higher. You
* If you're using MySQL, you'll need the ``MySQL-python`` package, version 1.2.1p2 or higher. You
will also want to read the database-specific :ref:`notes for the MySQL
backend <mysql-notes>`.
@@ -135,7 +135,6 @@ Django will need permission to create a test database.
.. _MySQL: http://www.mysql.com/
.. _psycopg: http://initd.org/pub/software/psycopg/
.. _compiled Windows version: http://stickpeople.com/projects/python/win-psycopg/
.. _MySQLdb: http://sourceforge.net/projects/mysql-python
.. _SQLite: http://www.sqlite.org/
.. _pysqlite: http://trac.edgewall.org/wiki/PySqlite
.. _cx_Oracle: http://cx-oracle.sourceforge.net/

View File

@@ -209,8 +209,8 @@ By default, Django uses the `dictConfig format`_.
``logging.dictConfig`` is a builtin library in Python 2.7. In
order to make this library available for users of earlier Python
versions, Django includes a copy as part of ``django.utils.log``.
If you have Python 2.7, the system native library will be used; if
you have Python 2.6 or earlier, Django's copy will be used.
If you have Python 2.7 or later, the system native library will be used; if
you have Python 2.6, Django's copy will be used.
In order to configure logging, you use :setting:`LOGGING` to define a
dictionary of logging settings. These settings describes the loggers,
@@ -218,10 +218,11 @@ handlers, filters and formatters that you want in your logging setup,
and the log levels and other properties that you want those components
to have.
Logging is configured immediately after settings have been loaded.
Since the loading of settings is one of the first things that Django
does, you can be certain that loggers are always ready for use in your
project code.
Logging is configured as soon as settings have been loaded
(either manually using :func:`~django.conf.settings.configure` or when at least
one setting is accessed). Since the loading of settings is one of the first
things that Django does, you can be certain that loggers are always ready for
use in your project code.
.. _dictConfig format: http://docs.python.org/library/logging.config.html#configuration-dictionary-schema

View File

@@ -43,7 +43,9 @@ page::
>>> page2.has_other_pages()
True
>>> page2.next_page_number()
3
Traceback (most recent call last):
...
EmptyPage: That page contains no results
>>> page2.previous_page_number()
1
>>> page2.start_index() # The 1-based index of the first item on this page
@@ -253,13 +255,19 @@ Methods
.. method:: Page.next_page_number()
Returns the next page number. Note that this is "dumb" and will return the
next page number regardless of whether a subsequent page exists.
Returns the next page number.
.. versionchanged:: 1.5
Raises :exc:`InvalidPage` if next page doesn't exist.
.. method:: Page.previous_page_number()
Returns the previous page number. Note that this is "dumb" and will return
the previous page number regardless of whether a previous page exists.
Returns the previous page number.
.. versionchanged:: 1.5
Raises :exc:`InvalidPage` if previous page doesn't exist.
.. method:: Page.start_index()

396
docs/topics/python3.txt Normal file
View File

@@ -0,0 +1,396 @@
===================
Porting to Python 3
===================
Django 1.5 is the first version of Django to support Python 3. The same code
runs both on Python 2 (≥ 2.6.5) and Python 3 (≥ 3.2), thanks to the six_
compatibility layer.
.. _six: http://packages.python.org/six/
This document is primarily targeted at authors of pluggable application
who want to support both Python 2 and 3. It also describes guidelines that
apply to Django's code.
Philosophy
==========
This document assumes that you are familiar with the changes between Python 2
and Python 3. If you aren't, read `Python's official porting guide`_ first.
Refreshing your knowledge of unicode handling on Python 2 and 3 will help; the
`Pragmatic Unicode`_ presentation is a good resource.
Django uses the *Python 2/3 Compatible Source* strategy. Of course, you're
free to chose another strategy for your own code, especially if you don't need
to stay compatible with Python 2. But authors of pluggable applications are
encouraged to use the same porting strategy as Django itself.
Writing compatible code is much easier if you target Python ≥ 2.6. You will
most likely take advantage of the compatibility functions introduced in Django
1.5, like :mod:`django.utils.six`, so your application will also require
Django ≥ 1.5.
Obviously, writing compatible source code adds some overhead, and that can
cause frustration. Django's developers have found that attempting to write
Python 3 code that's compatible with Python 2 is much more rewarding than the
opposite. Not only does that make your code more future-proof, but Python 3's
advantages (like the saner string handling) start shining quickly. Dealing
with Python 2 becomes a backwards compatibility requirement, and we as
developers are used to dealing with such constraints.
Porting tools provided by Django are inspired by this philosophy, and it's
reflected throughout this guide.
.. _Python's official porting guide: http://docs.python.org/py3k/howto/pyporting.html
.. _Pragmatic Unicode: http://nedbatchelder.com/text/unipain.html
Porting tips
============
Unicode literals
----------------
This step consists in:
- Adding ``from __future__ import unicode_literals`` at the top of your Python
modules -- it's best to put it in each and every module, otherwise you'll
keep checking the top of your files to see which mode is in effect;
- Removing the ``u`` prefix before unicode strings;
- Adding a ``b`` prefix before bytestrings.
Performing these changes systematically guarantees backwards compatibility.
However, Django applications generally don't need bytestrings, since Django
only exposes unicode interfaces to the programmer. Python 3 discourages using
bytestrings, except for binary data or byte-oriented interfaces. Python 2
makes bytestrings and unicode strings effectively interchangeable, as long as
they only contain ASCII data. Take advantage of this to use unicode strings
wherever possible and avoid the ``b`` prefixes.
.. note::
Python 2's ``u`` prefix is a syntax error in Python 3.2 but it will be
allowed again in Python 3.3 thanks to :pep:`414`. Thus, this
transformation is optional if you target Python ≥ 3.3. It's still
recommended, per the "write Python 3 code" philosophy.
String handling
---------------
Python 2's :class:`unicode` type was renamed :class:`str` in Python 3,
:class:`str` was renamed :class:`bytes`, and :class:`basestring` disappeared.
six_ provides :ref:`tools <string-handling-with-six>` to deal with these
changes.
Django also contains several string related classes and functions in the
:mod:`django.utils.encoding` and :mod:`django.utils.safestring` modules. Their
names used the words ``str``, which doesn't mean the same thing in Python 2
and Python 3, and ``unicode``, which doesn't exist in Python 3. In order to
avoid ambiguity and confusion these concepts were renamed ``bytes`` and
``text``.
Here are the name changes in :mod:`django.utils.encoding`:
================== ==================
Old name New name
================== ==================
``smart_str`` ``smart_bytes``
``smart_unicode`` ``smart_text``
``force_unicode`` ``force_text``
================== ==================
For backwards compatibility, the old names still work on Python 2. Under
Python 3, ``smart_str`` is an alias for ``smart_text``.
.. note::
:mod:`django.utils.encoding` was deeply refactored in Django 1.5 to
provide a more consistent API. Check its documentation for more
information.
:mod:`django.utils.safestring` is mostly used via the
:func:`~django.utils.safestring.mark_safe` and
:func:`~django.utils.safestring.mark_for_escaping` functions, which didn't
change. In case you're using the internals, here are the name changes:
================== ==================
Old name New name
================== ==================
``EscapeString`` ``EscapeBytes``
``EscapeUnicode`` ``EscapeText``
``SafeString`` ``SafeBytes``
``SafeUnicode`` ``SafeText``
================== ==================
For backwards compatibility, the old names still work on Python 2. Under
Python 3, ``EscapeString`` and ``SafeString`` are aliases for ``EscapeText``
and ``SafeText`` respectively.
:meth:`__str__` and :meth:`__unicode__` methods
-----------------------------------------------
In Python 2, the object model specifies :meth:`__str__` and
:meth:`__unicode__` methods. If these methods exist, they must return
:class:`str` (bytes) and :class:`unicode` (text) respectively.
The ``print`` statement and the :func:`str` built-in call :meth:`__str__` to
determine the human-readable representation of an object. The :func:`unicode`
built-in calls :meth:`__unicode__` if it exists, and otherwise falls back to
:meth:`__str__` and decodes the result with the system encoding. Conversely,
the :class:`~django.db.models.Model` base class automatically derives
:meth:`__str__` from :meth:`__unicode__` by encoding to UTF-8.
In Python 3, there's simply :meth:`__str__`, which must return :class:`str`
(text).
(It is also possible to define :meth:`__bytes__`, but Django application have
little use for that method, because they hardly ever deal with
:class:`bytes`.)
Django provides a simple way to define :meth:`__str__` and :meth:`__unicode__`
methods that work on Python 2 and 3: you must define a :meth:`__str__` method
returning text and to apply the
:func:`~django.utils.encoding.python_2_unicode_compatible` decorator.
On Python 3, the decorator is a no-op. On Python 2, it defines appropriate
:meth:`__unicode__` and :meth:`__str__` methods (replacing the original
:meth:`__str__` method in the process). Here's an example::
from __future__ import unicode_literals
from django.utils.encoding import python_2_unicode_compatible
@python_2_unicode_compatible
class MyClass(object):
def __str__(self):
return "Instance of my class"
This technique is the best match for Django's porting philosophy.
Finally, note that :meth:`__repr__` must return a :class:`str` on all versions
of Python.
:class:`dict` and :class:`dict`-like classes
--------------------------------------------
:meth:`dict.keys`, :meth:`dict.items` and :meth:`dict.values` return lists in
Python 2 and iterators in Python 3. :class:`~django.http.QueryDict` and the
:class:`dict`-like classes defined in :mod:`django.utils.datastructures`
behave likewise in Python 3.
six_ provides compatibility functions to work around this change:
:func:`~six.iterkeys`, :func:`~six.iteritems`, and :func:`~six.itervalues`.
Django's bundled version adds :func:`~django.utils.six.iterlists` for
:class:`~django.utils.datastructures.MultiValueDict` and its subclasses.
:class:`~django.http.HttpRequest` and :class:`~django.http.HttpResponse` objects
--------------------------------------------------------------------------------
According to :pep:`3333`:
- headers are always :class:`str` objects,
- input and output streams are always :class:`bytes` objects.
Specifically, :attr:`HttpResponse.content <django.http.HttpResponse.content>`
contains :class:`bytes`, which may become an issue if you compare it with a
:class:`str` in your tests. The preferred solution is to rely on
:meth:`~django.test.TestCase.assertContains` and
:meth:`~django.test.TestCase.assertNotContains`. These methods accept a
response and a unicode string as arguments.
Coding guidelines
=================
The following guidelines are enforced in Django's source code. They're also
recommended for third-party application who follow the same porting strategy.
Syntax requirements
-------------------
Unicode
~~~~~~~
In Python 3, all strings are considered Unicode by default. The ``unicode``
type from Python 2 is called ``str`` in Python 3, and ``str`` becomes
``bytes``.
You mustn't use the ``u`` prefix before a unicode string literal because it's
a syntax error in Python 3.2. You must prefix byte strings with ``b``.
In order to enable the same behavior in Python 2, every module must import
``unicode_literals`` from ``__future__``::
from __future__ import unicode_literals
my_string = "This is an unicode literal"
my_bytestring = b"This is a bytestring"
If you need a byte string literal under Python 2 and a unicode string literal
under Python 3, use the :func:`str` builtin::
str('my string')
In Python 3, there aren't any automatic conversions between :class:`str` and
:class:`bytes`, and the :mod:`codecs` module became more strict.
:meth:`str.decode` always returns :class:`bytes`, and :meth:`bytes.decode`
always returns :class:`str`. As a consequence, the following pattern is
sometimes necessary::
value = value.encode('ascii', 'ignore').decode('ascii')
Be cautious if you have to `slice bytestrings`_.
.. _slice bytestrings: http://docs.python.org/py3k/howto/pyporting.html#bytes-literals
Exceptions
~~~~~~~~~~
When you capture exceptions, use the ``as`` keyword::
try:
...
except MyException as exc:
...
This older syntax was removed in Python 3::
try:
...
except MyException, exc: # Don't do that!
...
The syntax to reraise an exception with a different traceback also changed.
Use :func:`six.reraise`.
Magic methods
-------------
Use the patterns below to handle magic methods renamed in Python 3.
Iterators
~~~~~~~~~
::
class MyIterator(object):
def __iter__(self):
return self # implement some logic here
def __next__(self):
raise StopIteration # implement some logic here
next = __next__ # Python 2 compatibility
Boolean evaluation
~~~~~~~~~~~~~~~~~~
::
class MyBoolean(object):
def __bool__(self):
return True # implement some logic here
__nonzero__ = __bool__ # Python 2 compatibility
Division
~~~~~~~~
::
class MyDivisible(object):
def __truediv__(self, other):
return self / other # implement some logic here
__div__ = __truediv__ # Python 2 compatibility
def __itruediv__(self, other):
return self // other # implement some logic here
__idiv__ = __itruediv__ # Python 2 compatibility
.. module: django.utils.six
Writing compatible code with six
--------------------------------
six_ is the canonical compatibility library for supporting Python 2 and 3 in
a single codebase. Read its documentation!
:mod:`six` is bundled with Django: you can import it as :mod:`django.utils.six`.
Here are the most common changes required to write compatible code.
.. _string-handling-with-six:
String handling
~~~~~~~~~~~~~~~
The ``basestring`` and ``unicode`` types were removed in Python 3, and the
meaning of ``str`` changed. To test these types, use the following idioms::
isinstance(myvalue, six.string_types) # replacement for basestring
isinstance(myvalue, six.text_type) # replacement for unicode
isinstance(myvalue, bytes) # replacement for str
Python ≥ 2.6 provides ``bytes`` as an alias for ``str``, so you don't need
:attr:`six.binary_type`.
``long``
~~~~~~~~
The ``long`` type no longer exists in Python 3. ``1L`` is a syntax error. Use
:data:`six.integer_types` check if a value is an integer or a long::
isinstance(myvalue, six.integer_types) # replacement for (int, long)
``xrange``
~~~~~~~~~~
Import :func:`six.moves.xrange` wherever you use ``xrange``.
Moved modules
~~~~~~~~~~~~~
Some modules were renamed in Python 3. The :mod:`django.utils.six.moves
<six.moves>` module provides a compatible location to import them.
The ``urllib``, ``urllib2`` and ``urlparse`` modules were reworked in depth
and :mod:`django.utils.six.moves <six.moves>` doesn't handle them. Django
explicitly tries both locations, as follows::
try:
from urllib.parse import urlparse, urlunparse
except ImportError: # Python 2
from urlparse import urlparse, urlunparse
PY3
~~~
If you need different code in Python 2 and Python 3, check :data:`six.PY3`::
if six.PY3:
# do stuff Python 3-wise
else:
# do stuff Python 2-wise
This is a last resort solution when :mod:`six` doesn't provide an appropriate
function.
.. module:: django.utils.six
Customizations of six
---------------------
The version of six bundled with Django includes one extra function:
.. function:: iterlists(MultiValueDict)
Returns an iterator over the lists of values of a
:class:`~django.utils.datastructures.MultiValueDict`. This replaces
:meth:`~django.utils.datastructures.MultiValueDict.iterlists()` on Python
2 and :meth:`~django.utils.datastructures.MultiValueDict.lists()` on
Python 3.
In addition to six' defaults moves, Django's version provides ``thread`` as
``_thread`` and ``dummy_thread`` as ``_dummy_thread``.

View File

@@ -122,22 +122,19 @@ transferred between client and server, and in some cases -- **active** network
attackers -- to alter data that is sent in either direction.
If you want the protection that HTTPS provides, and have enabled it on your
server, there are some additional steps to consider to ensure that sensitive
information is not leaked:
server, there are some additional steps you may need:
* If necessary, set :setting:`SECURE_PROXY_SSL_HEADER`, ensuring that you have
understood the warnings there thoroughly. Failure to do this can result
in CSRF vulnerabilities, and failure to do it correctly can also be
dangerous!
* Set up redirection so that requests over HTTP are redirected to HTTPS.
It is possible to do this with a piece of Django middleware. However, this has
problems for the common case of a Django app running behind a reverse
proxy. Often, reverse proxies are configured to set the ``X-Forwarded-SSL``
header (or equivalent) if the incoming connection was HTTPS, and the absence
of this header could be used to detect a request that was not HTTPS. However,
this method usually cannot be relied on, as a client, or a malicious active
network attacker, could also set this header.
So, for the case of a reverse proxy, it is recommended that the main Web
server should be configured to do the redirect to HTTPS, or configured to send
HTTP requests to an app that unconditionally redirects to HTTPS.
This could be done using a custom middleware. Please note the caveats under
:setting:`SECURE_PROXY_SSL_HEADER`. For the case of a reverse proxy, it may be
easier or more secure to configure the main Web server to do the redirect to
HTTPS.
* Use 'secure' cookies.

View File

@@ -173,12 +173,12 @@ In particular, :ref:`lazy translation objects <lazy-translations>` need a
import json
from django.utils.functional import Promise
from django.utils.encoding import force_unicode
from django.utils.encoding import force_text
class LazyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Promise):
return force_unicode(obj)
return force_text(obj)
return super(LazyEncoder, self).default(obj)
.. _special encoder: http://docs.python.org/library/json.html#encoders-and-decoders
@@ -188,11 +188,6 @@ In particular, :ref:`lazy translation objects <lazy-translations>` need a
Natural keys
------------
.. versionadded:: 1.2
The ability to use natural keys when serializing/deserializing data was
added in the 1.2 release.
The default serialization strategy for foreign keys and many-to-many relations
is to serialize the value of the primary key(s) of the objects in the relation.
This strategy works well for most objects, but it can cause difficulty in some

View File

@@ -52,10 +52,10 @@ called when the signal is sent by using the
:meth:`.Signal.connect` method:
.. method:: Signal.connect(receiver, [sender=None, weak=True, dispatch_uid=None])
:param receiver: The callback function which will be connected to this
signal. See :ref:`receiver-functions` for more information.
:param sender: Specifies a particular sender to receive signals from. See
:ref:`connecting-to-specific-signals` for more information.
@@ -129,10 +129,17 @@ receiver:
Now, our ``my_callback`` function will be called each time a request finishes.
Note that ``receiver`` can also take a list of signals to connect a function
to.
.. versionadded:: 1.3
The ``receiver`` decorator was added in Django 1.3.
.. versionchanged:: 1.5
The ability to pass a list of signals was added.
.. admonition:: Where should this code live?
You can put signal handling and registration code anywhere you like.
@@ -182,7 +189,7 @@ Preventing duplicate signals
In some circumstances, the module in which you are connecting signals may be
imported multiple times. This can cause your receiver function to be
registered more than once, and thus called multiples times for a single signal
event.
event.
If this behavior is problematic (such as when using signals to
send an email whenever a model is saved), pass a unique identifier as
@@ -228,7 +235,7 @@ Remember that you're allowed to change this list of arguments at any time, so ge
Sending signals
---------------
There are two ways to send send signals in Django.
There are two ways to send signals in Django.
.. method:: Signal.send(sender, **kwargs)
.. method:: Signal.send_robust(sender, **kwargs)

View File

@@ -226,6 +226,10 @@ tags:
Athlete: {{ athlete_list.0.name }}
{% endif %}
While the above example works, be aware that most template filters return
strings, so mathematical comparisons using filters will generally not work
as you expect. :tfilter:`length` is an exception.
:ttag:`block` and :ttag:`extends`
Set up `template inheritance`_ (see below), a powerful way
of cutting down on "boilerplate" in templates.

View File

@@ -291,9 +291,6 @@ label::
$ ./manage.py test animals.AnimalTestCase.test_animals_can_speak
.. versionadded:: 1.2
The ability to select individual doctests was added.
You can use the same rules if you're using doctests. Django will use the
test label as a path to the test method or class that you want to run.
If your ``models.py`` or ``tests.py`` has a function with a doctest, or
@@ -311,9 +308,6 @@ If you're using a ``__test__`` dictionary to specify doctests for a
module, Django will use the label as a key in the ``__test__`` dictionary
for defined in ``models.py`` and ``tests.py``.
.. versionadded:: 1.2
You can now trigger a graceful exit from a test run by pressing ``Ctrl-C``.
If you press ``Ctrl-C`` while the tests are running, the test runner will
wait for the currently running test to complete and then exit gracefully.
During a graceful exit the test runner will output details of any test
@@ -392,8 +386,6 @@ advanced settings.
Testing master/slave configurations
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 1.2
If you're testing a multiple database configuration with master/slave
replication, this strategy of creating test databases poses a problem.
When the test databases are created, there won't be any replication,
@@ -486,6 +478,32 @@ If there are any circular dependencies in the
:setting:`TEST_DEPENDENCIES` definition, an ``ImproperlyConfigured``
exception will be raised.
Order in which tests are executed
---------------------------------
In order to guarantee that all ``TestCase`` code starts with a clean database,
the Django test runner reorders tests in the following way:
* First, all unittests (including :class:`unittest.TestCase`,
:class:`~django.test.SimpleTestCase`, :class:`~django.test.TestCase` and
:class:`~django.test.TransactionTestCase`) are run with no particular ordering
guaranteed nor enforced among them.
* Then any other tests (e.g. doctests) that may alter the database without
restoring it to its original state are run.
.. versionchanged:: 1.5
Before Django 1.5, the only guarantee was that
:class:`~django.test.TestCase` tests were always ran first, before any other
tests.
.. note::
The new ordering of tests may reveal unexpected dependencies on test case
ordering. This is the case with doctests that relied on state left in the
database by a given :class:`~django.test.TransactionTestCase` test, they
must be updated to be able to run independently.
Other test conditions
---------------------
@@ -553,6 +571,21 @@ failed and erroneous tests. If all the tests pass, the return code is 0. This
feature is useful if you're using the test-runner script in a shell script and
need to test for success or failure at that level.
Speeding up the tests
---------------------
In recent versions of Django, the default password hasher is rather slow by
design. If during your tests you are authenticating many users, you may want
to use a custom settings file and set the :setting:`PASSWORD_HASHERS` setting
to a faster hashing algorithm::
PASSWORD_HASHERS = (
'django.contrib.auth.hashers.MD5PasswordHasher',
)
Don't forget to also include in :setting:`PASSWORD_HASHERS` any hashing
algorithm used in fixtures, if any.
Testing tools
=============
@@ -650,8 +683,6 @@ Note a few important things about how the test client works:
* By default, the test client will disable any CSRF checks
performed by your site.
.. versionadded:: 1.2.2
If, for some reason, you *want* the test client to perform CSRF
checks, you can create an instance of the test client that
enforces CSRF checks. To do this, pass in the
@@ -664,10 +695,23 @@ Note a few important things about how the test client works:
Making requests
~~~~~~~~~~~~~~~
Use the ``django.test.client.Client`` class to make requests. It requires no
arguments at time of construction:
Use the ``django.test.client.Client`` class to make requests.
.. class:: Client()
.. class:: Client(enforce_csrf_checks=False, **defaults)
It requires no arguments at time of construction. However, you can use
keywords arguments to specify some default headers. For example, this will
send a ``User-Agent`` HTTP header in each request::
>>> c = Client(HTTP_USER_AGENT='Mozilla/5.0')
The values from the ``extra`` keywords arguments passed to
:meth:`~django.test.client.Client.get()`,
:meth:`~django.test.client.Client.post()`, etc. have precedence over
the defaults passed to the class constructor.
The ``enforce_csrf_checks`` argument can be used to test CSRF
protection (see above).
Once you have a ``Client`` instance, you can call any of the following
methods:
@@ -1091,8 +1135,11 @@ The following is a simple unit test using the request factory::
response = my_view(request)
self.assertEqual(response.status_code, 200)
TestCase
--------
Test cases
----------
Provided test case classes
~~~~~~~~~~~~~~~~~~~~~~~~~~
.. currentmodule:: django.test
@@ -1106,16 +1153,19 @@ Normal Python unit test classes extend a base class of
Hierarchy of Django unit testing classes
TestCase
^^^^^^^^
.. class:: TestCase()
This class provides some additional capabilities that can be useful for testing
Web sites.
Converting a normal :class:`unittest.TestCase` to a Django :class:`TestCase` is
easy: just change the base class of your test from :class:`unittest.TestCase` to
:class:`django.test.TestCase`. All of the standard Python unit test
functionality will continue to be available, but it will be augmented with some
useful additions, including:
easy: Just change the base class of your test from `'unittest.TestCase'` to
`'django.test.TestCase'`. All of the standard Python unit test functionality
will continue to be available, but it will be augmented with some useful
additions, including:
* Automatic loading of fixtures.
@@ -1123,11 +1173,18 @@ useful additions, including:
* Creates a TestClient instance.
* Django-specific assertions for testing for things
like redirection and form errors.
* Django-specific assertions for testing for things like redirection and form
errors.
.. versionchanged:: 1.5
The order in which tests are run has changed. See `Order in which tests are
executed`_.
``TestCase`` inherits from :class:`~django.test.TransactionTestCase`.
TransactionTestCase
^^^^^^^^^^^^^^^^^^^
.. class:: TransactionTestCase()
Django ``TestCase`` classes make use of database transaction facilities, if
@@ -1139,38 +1196,66 @@ behavior, you should use a Django ``TransactionTestCase``.
``TransactionTestCase`` and ``TestCase`` are identical except for the manner
in which the database is reset to a known state and the ability for test code
to test the effects of commit and rollback. A ``TransactionTestCase`` resets
the database before the test runs by truncating all tables and reloading
initial data. A ``TransactionTestCase`` may call commit and rollback and
observe the effects of these calls on the database.
to test the effects of commit and rollback:
A ``TestCase``, on the other hand, does not truncate tables and reload initial
data at the beginning of a test. Instead, it encloses the test code in a
database transaction that is rolled back at the end of the test. It also
prevents the code under test from issuing any commit or rollback operations
on the database, to ensure that the rollback at the end of the test restores
the database to its initial state. In order to guarantee that all ``TestCase``
code starts with a clean database, the Django test runner runs all ``TestCase``
tests first, before any other tests (e.g. doctests) that may alter the
database without restoring it to its original state.
* A ``TransactionTestCase`` resets the database after the test runs by
truncating all tables. A ``TransactionTestCase`` may call commit and rollback
and observe the effects of these calls on the database.
When running on a database that does not support rollback (e.g. MySQL with the
MyISAM storage engine), ``TestCase`` falls back to initializing the database
by truncating tables and reloading initial data.
* A ``TestCase``, on the other hand, does not truncate tables after a test.
Instead, it encloses the test code in a database transaction that is rolled
back at the end of the test. It also prevents the code under test from
issuing any commit or rollback operations on the database, to ensure that the
rollback at the end of the test restores the database to its initial state.
When running on a database that does not support rollback (e.g. MySQL with the
MyISAM storage engine), ``TestCase`` falls back to initializing the database
by truncating tables and reloading initial data.
.. note::
.. versionchanged:: 1.5
Prior to 1.5, ``TransactionTestCase`` flushed the database tables *before*
each test. In Django 1.5, this is instead done *after* the test has been run.
When the flush took place before the test, it was guaranteed that primary
key values started at one in :class:`~django.test.TransactionTestCase`
tests.
Tests should not depend on this behaviour, but for legacy tests that do, the
:attr:`~TransactionTestCase.reset_sequences` attribute can be used until
the test has been properly updated.
.. versionchanged:: 1.5
The order in which tests are run has changed. See `Order in which tests are
executed`_.
``TransactionTestCase`` inherits from :class:`~django.test.SimpleTestCase`.
.. note::
The ``TestCase`` use of rollback to un-do the effects of the test code
may reveal previously-undetected errors in test code. For example,
test code that assumes primary keys values will be assigned starting at
one may find that assumption no longer holds true when rollbacks instead
of table truncation are being used to reset the database. Similarly,
the reordering of tests so that all ``TestCase`` classes run first may
reveal unexpected dependencies on test case ordering. In such cases a
quick fix is to switch the ``TestCase`` to a ``TransactionTestCase``.
A better long-term fix, that allows the test to take advantage of the
speed benefit of ``TestCase``, is to fix the underlying test problem.
.. attribute:: TransactionTestCase.reset_sequences
.. versionadded:: 1.5
Setting ``reset_sequences = True`` on a ``TransactionTestCase`` will make
sure sequences are always reset before the test run::
class TestsThatDependsOnPrimaryKeySequences(TransactionTestCase):
reset_sequences = True
def test_animal_pk(self):
lion = Animal.objects.create(name="lion", sound="roar")
# lion.pk is guaranteed to always be 1
self.assertEqual(lion.pk, 1)
Unless you are explicitly testing primary keys sequence numbers, it is
recommended that you do not hard code primary key values in tests.
Using ``reset_sequences = True`` will slow down the test, since the primary
key reset is an relatively expensive database operation.
SimpleTestCase
^^^^^^^^^^^^^^
.. class:: SimpleTestCase()
@@ -1376,8 +1461,6 @@ Multi-database support
.. attribute:: TestCase.multi_db
.. versionadded:: 1.2
Django sets up a test database corresponding to every database that is
defined in the :setting:`DATABASES` definition in your settings
file. However, a big part of the time taken to run a Django TestCase
@@ -1501,9 +1584,6 @@ Assertions
.. currentmodule:: django.test
.. versionchanged:: 1.2
Added ``msg_prefix`` argument.
As Python's normal :class:`unittest.TestCase` class implements assertion methods
such as :meth:`~unittest.TestCase.assertTrue` and
:meth:`~unittest.TestCase.assertEqual`, Django's custom :class:`TestCase` class
@@ -1927,7 +2007,7 @@ out the `full reference`_ for more details.
.. _Selenium: http://seleniumhq.org/
.. _selenium package: http://pypi.python.org/pypi/selenium
.. _full reference: http://readthedocs.org/docs/selenium-python/en/latest/api.html
.. _full reference: http://selenium-python.readthedocs.org/en/latest/api.html
.. _Firefox: http://www.mozilla.com/firefox/
.. note::
@@ -2011,9 +2091,6 @@ process to satisfy whatever testing requirements you may have.
Defining a test runner
----------------------
.. versionchanged:: 1.2
Prior to 1.2, test runners were a single function, not a class.
.. currentmodule:: django.test.simple
A test runner is a class defining a ``run_tests()`` method. Django ships