Commits

Samuel Martin committed a6ed4e0

Ajout fichers manquants topics

Comments (0)

Files changed (37)

+=============================
+User authentication in Django
+=============================
+
+.. module:: django.contrib.auth
+   :synopsis: Django's authentication framework.
+
+Django comes with a user authentication system. It handles user accounts,
+groups, permissions and cookie-based user sessions. This document explains how
+things work.
+
+Overview
+========
+
+The auth system consists of:
+
+    * Users
+    * Permissions: Binary (yes/no) flags designating whether a user may perform
+      a certain task.
+    * Groups: A generic way of applying labels and permissions to more than one
+      user.
+
+Installation
+============
+
+Authentication support is bundled as a Django application in
+``django.contrib.auth``. To install it, do the following:
+
+    1. Put ``'django.contrib.auth'`` and ``'django.contrib.contenttypes'`` in
+       your :setting:`INSTALLED_APPS` setting.
+       (The :class:`~django.contrib.auth.models.Permission` model in
+       :mod:`django.contrib.auth` depends on :mod:`django.contrib.contenttypes`.)
+    2. Run the command ``manage.py syncdb``.
+
+Note that the default :file:`settings.py` file created by
+:djadmin:`django-admin.py startproject <startproject>` includes
+``'django.contrib.auth'`` and ``'django.contrib.contenttypes'`` in
+:setting:`INSTALLED_APPS` for convenience.  If your :setting:`INSTALLED_APPS`
+already contains these apps, feel free to run :djadmin:`manage.py syncdb
+<syncdb>` again; you can run that command as many times as you'd like, and each
+time it'll only install what's needed.
+
+The :djadmin:`syncdb` command creates the necessary database tables, creates
+permission objects for all installed apps that need 'em, and prompts you to
+create a superuser account the first time you run it.
+
+Once you've taken those steps, that's it.
+
+Users
+=====
+
+.. class:: models.User
+
+API reference
+-------------
+
+Fields
+~~~~~~
+
+.. class:: models.User
+
+    :class:`~django.contrib.auth.models.User` objects have the following
+    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.
+
+    .. attribute:: models.User.first_name
+
+        Optional. 30 characters or fewer.
+
+    .. attribute:: models.User.last_name
+
+        Optional. 30 characters or fewer.
+
+    .. attribute:: models.User.email
+
+        Optional. Email address.
+
+    .. attribute:: models.User.password
+
+        Required. A hash of, and metadata about, the password. (Django doesn't
+        store the raw password.) Raw passwords can be arbitrarily long and can
+        contain any character. See the "Passwords" section below.
+
+    .. attribute:: models.User.is_staff
+
+        Boolean. Designates whether this user can access the admin site.
+
+    .. attribute:: models.User.is_active
+
+        Boolean. Designates whether this user account should be considered
+        active. We recommend that you set this flag to ``False`` instead of
+        deleting accounts; that way, if your applications have any foreign keys
+        to users, the foreign keys won't break.
+
+        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
+        admin. All of those functions/methods will return ``False`` for
+        inactive users.
+
+    .. attribute:: models.User.is_superuser
+
+        Boolean. Designates that this user has all permissions without
+        explicitly assigning them.
+
+    .. attribute:: models.User.last_login
+
+        A datetime of the user's last login. Is set to the current date/time by
+        default.
+
+    .. attribute:: models.User.date_joined
+
+        A datetime designating when the account was created. Is set to the
+        current date/time by default when the account is created.
+
+Methods
+~~~~~~~
+
+.. class:: models.User
+
+    :class:`~django.contrib.auth.models.User` objects have two many-to-many
+    fields: models.User. ``groups`` and ``user_permissions``.
+    :class:`~django.contrib.auth.models.User` objects can access their related
+    objects in the same way as any other :doc:`Django model
+    </topics/db/models>`:
+
+    .. code-block:: python
+
+        myuser.groups = [group_list]
+        myuser.groups.add(group, group, ...)
+        myuser.groups.remove(group, group, ...)
+        myuser.groups.clear()
+        myuser.user_permissions = [permission_list]
+        myuser.user_permissions.add(permission, permission, ...)
+        myuser.user_permissions.remove(permission, permission, ...)
+        myuser.user_permissions.clear()
+
+    In addition to those automatic API methods,
+    :class:`~django.contrib.auth.models.User` objects have the following custom
+    methods:
+
+    .. method:: models.User.is_anonymous()
+
+        Always returns ``False``. This is a way of differentiating
+        :class:`~django.contrib.auth.models.User` and
+        :class:`~django.contrib.auth.models.AnonymousUser` objects.
+        Generally, you should prefer using
+        :meth:`~django.contrib.auth.models.User.is_authenticated()` to this
+        method.
+
+    .. method:: models.User.is_authenticated()
+
+        Always returns ``True``. This is a way to tell if the user has been
+        authenticated. This does not imply any permissions, and doesn't check
+        if the user is active - it only indicates that the user has provided a
+        valid username and password.
+
+    .. method:: models.User.get_full_name()
+
+        Returns the :attr:`~django.contrib.auth.models.User.first_name` plus
+        the :attr:`~django.contrib.auth.models.User.last_name`, with a space in
+        between.
+
+    .. method:: models.User.set_password(raw_password)
+
+        Sets the user's password to the given raw string, taking care of the
+        password hashing. Doesn't save the
+        :class:`~django.contrib.auth.models.User` object.
+
+    .. method:: models.User.check_password(raw_password)
+
+        Returns ``True`` if the given raw string is the correct password for
+        the user. (This takes care of the password hashing in making the
+        comparison.)
+
+    .. method:: models.User.set_unusable_password()
+
+        Marks the user as having no password set.  This isn't the same as
+        having a blank string for a password.
+        :meth:`~django.contrib.auth.models.User.check_password()` for this user
+        will never return ``True``. Doesn't save the
+        :class:`~django.contrib.auth.models.User` object.
+
+        You may need this if authentication for your application takes place
+        against an existing external source such as an LDAP directory.
+
+    .. method:: models.User.has_usable_password()
+
+        Returns ``False`` if
+        :meth:`~django.contrib.auth.models.User.set_unusable_password()` has
+        been called for this user.
+
+    .. method:: models.User.get_group_permissions(obj=None)
+
+        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.
+
+    .. method:: models.User.get_all_permissions(obj=None)
+
+        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.
+
+    .. method:: models.User.has_perm(perm, obj=None)
+
+        Returns ``True`` if the user has the specified permission, where perm is
+        in the format ``"<app label>.<permission codename>"``. (see
+        `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.
+
+    .. method:: models.User.has_perms(perm_list, obj=None)
+
+        Returns ``True`` if the user has each of the specified permissions,
+        where each perm is in the format
+        ``"<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.
+
+    .. method:: models.User.has_module_perms(package_name)
+
+        Returns ``True`` if the user has any permissions in the given package
+        (the Django app label). If the user is inactive, this method will
+        always return ``False``.
+
+    .. method:: models.User.email_user(subject, message, from_email=None)
+
+        Sends an email to the user. If
+        :attr:`~django.contrib.auth.models.User.from_email` is ``None``, Django
+        uses the :setting:`DEFAULT_FROM_EMAIL`.
+
+    .. method:: models.User.get_profile()
+
+        Returns a site-specific profile for this user. Raises
+        :exc:`django.contrib.auth.models.SiteProfileNotAvailable` if the
+        current site doesn't allow profiles. For information on how to define a
+        site-specific user profile, see the section on `storing additional user
+        information`_ below.
+
+.. _storing additional user information: #storing-additional-information-about-users
+
+Manager functions
+~~~~~~~~~~~~~~~~~
+
+.. class:: models.UserManager
+
+    The :class:`~django.contrib.auth.models.User` model has a custom manager
+    that has the following helper functions:
+
+    .. method:: models.UserManager.create_user(username, email, password=None)
+
+        Creates, saves and returns a :class:`~django.contrib.auth.models.User`.
+
+        The :attr:`~django.contrib.auth.models.User.username` and
+        :attr:`~django.contrib.auth.models.User.password` are set as given. The
+        domain portion of :attr:`~django.contrib.auth.models.User.email` is
+        automatically converted to lowercase, and the returned
+        :class:`~django.contrib.auth.models.User` object will have
+        :attr:`~models.User.is_active` set to ``True``.
+
+        If no password is provided,
+        :meth:`~django.contrib.auth.models.User.set_unusable_password()` will
+        be called.
+
+        See `Creating users`_ for example usage.
+
+    .. method:: models.UserManager.make_random_password(length=10, allowed_chars='abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789')
+
+        Returns a random password with the given length and given string of
+        allowed characters. (Note that the default value of ``allowed_chars``
+        doesn't contain letters that can cause user confusion, including:
+
+            * ``i``, ``l``, ``I``, and ``1`` (lowercase letter i, lowercase
+              letter L, uppercase letter i, and the number one)
+            * ``o``, ``O``, and ``0`` (uppercase letter o, lowercase letter o,
+              and zero)
+
+Basic usage
+-----------
+
+.. _topics-auth-creating-users:
+
+Creating users
+~~~~~~~~~~~~~~
+
+The most basic way to create users is to use the
+:meth:`~django.contrib.auth.models.UserManager.create_user` helper function
+that comes with Django::
+
+    >>> from django.contrib.auth.models import User
+    >>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')
+
+    # At this point, user is a User object that has already been saved
+    # to the database. You can continue to change its attributes
+    # if you want to change other fields.
+    >>> user.is_staff = True
+    >>> user.save()
+
+You can also create users using the Django admin site. Assuming you've enabled
+the admin site and hooked it to the URL ``/admin/``, the "Add user" page is at
+``/admin/auth/user/add/``. You should also see a link to "Users" in the "Auth"
+section of the main admin index page. The "Add user" admin page is different
+than standard admin pages in that it requires you to choose a username and
+password before allowing you to edit the rest of the user's fields.
+
+Also note: if you want your own user account to be able to create users using
+the Django admin site, you'll need to give yourself permission to add users
+*and* change users (i.e., the "Add user" and "Change user" permissions). If
+your account has permission to add users but not to change them, you won't be
+able to add users. Why? Because if you have permission to add users, you have
+the power to create superusers, which can then, in turn, change other users. So
+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
+they both match, the new password will be changed immediately. If you
+do not supply a user, the command will attempt to change the password
+whose username matches the current user.
+
+You can also change a password programmatically, using
+:meth:`~django.contrib.auth.models.User.set_password()`:
+
+.. code-block:: python
+
+    >>> from django.contrib.auth.models import User
+    >>> u = User.objects.get(username__exact='john')
+    >>> u.set_password('new password')
+    >>> u.save()
+
+Don't set the :attr:`~django.contrib.auth.models.User.password` attribute
+directly unless you know what you're doing. This is explained in the next
+section.
+
+Passwords
+---------
+
+The :attr:`~django.contrib.auth.models.User.password` attribute of a
+:class:`~django.contrib.auth.models.User` object is a string in this format::
+
+    hashtype$salt$hash
+
+That's hashtype, salt and hash, separated by the dollar-sign character.
+
+Hashtype is either ``sha1`` (default), ``md5`` or ``crypt`` -- the algorithm
+used to perform a one-way hash of the password. Salt is a random string used
+to salt the raw password to create the hash. Note that the ``crypt`` method is
+only supported on platforms that have the standard Python ``crypt`` module
+available.
+
+For example::
+
+    sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4
+
+The :meth:`~django.contrib.auth.models.User.set_password` and
+:meth:`~django.contrib.auth.models.User.check_password` functions handle the
+setting and checking of these values behind the scenes.
+
+Previous Django versions, such as 0.90, used simple MD5 hashes without password
+salts. For backwards compatibility, those are still supported; they'll be
+converted automatically to the new style the first time
+:meth:`~django.contrib.auth.models.User.check_password()` works correctly for
+a given user.
+
+Anonymous users
+---------------
+
+.. class:: models.AnonymousUser
+
+    :class:`django.contrib.auth.models.AnonymousUser` is a class that
+    implements the :class:`django.contrib.auth.models.User` interface, with
+    these differences:
+
+    * :attr:`~django.contrib.auth.models.User.id` is always ``None``.
+    * :attr:`~django.contrib.auth.models.User.is_staff` and
+      :attr:`~django.contrib.auth.models.User.is_superuser` are always
+      ``False``.
+    * :attr:`~django.contrib.auth.models.User.is_active` is always ``False``.
+    * :attr:`~django.contrib.auth.models.User.groups` and
+      :attr:`~django.contrib.auth.models.User.user_permissions` are always
+      empty.
+    * :meth:`~django.contrib.auth.models.User.is_anonymous()` returns ``True``
+      instead of ``False``.
+    * :meth:`~django.contrib.auth.models.User.is_authenticated()` returns
+      ``False`` instead of ``True``.
+    * :meth:`~django.contrib.auth.models.User.set_password()`,
+      :meth:`~django.contrib.auth.models.User.check_password()`,
+      :meth:`~django.contrib.auth.models.User.save()`,
+      :meth:`~django.contrib.auth.models.User.delete()`,
+      :meth:`~django.contrib.auth.models.User.set_groups()` and
+      :meth:`~django.contrib.auth.models.User.set_permissions()` raise
+      :exc:`NotImplementedError`.
+
+In practice, you probably won't need to use
+:class:`~django.contrib.auth.models.AnonymousUser` objects on your own, but
+they're used by Web requests, as explained in the next section.
+
+.. _topics-auth-creating-superusers:
+
+Creating superusers
+-------------------
+
+:djadmin:`manage.py syncdb <syncdb>` prompts you to create a superuser the
+first time you run it after adding ``'django.contrib.auth'`` to your
+:setting:`INSTALLED_APPS`. If you need to create a superuser at a later date,
+you can use a command line utility::
+
+    manage.py createsuperuser --username=joe --email=joe@example.com
+
+You will be prompted for a password. After you enter one, the user will be
+created immediately. If you leave off the :djadminopt:`--username` or the
+:djadminopt:`--email` options, it will prompt you for those values.
+
+If you're using an older release of Django, the old way of creating a superuser
+on the command line still works::
+
+    python /path/to/django/contrib/auth/create_superuser.py
+
+...where :file:`/path/to` is the path to the Django codebase on your
+filesystem. The ``manage.py`` command is preferred because it figures out the
+correct path and environment for you.
+
+.. _auth-profiles:
+
+Storing additional information about users
+------------------------------------------
+
+If you'd like to store additional information related to your users, Django
+provides a method to specify a site-specific related model -- termed a "user
+profile" -- for this purpose.
+
+To make use of this feature, define a model with fields for the
+additional information you'd like to store, or additional methods
+you'd like to have available, and also add a
+:class:`~django.db.models.Field.OneToOneField` named ``user`` from your model
+to the :class:`~django.contrib.auth.models.User` model. This will ensure only
+one instance of your model can be created for each
+:class:`~django.contrib.auth.models.User`.
+
+To indicate that this model is the user profile model for a given site, fill in
+the setting :setting:`AUTH_PROFILE_MODULE` with a string consisting of the
+following items, separated by a dot:
+
+1. The name of the application (case sensitive) in which the user
+   profile model is defined (in other words, the
+   name which was passed to :djadmin:`manage.py startapp <startapp>` to create
+   the application).
+
+2. The name of the model (not case sensitive) class.
+
+For example, if the profile model was a class named ``UserProfile`` and was
+defined inside an application named ``accounts``, the appropriate setting would
+be::
+
+    AUTH_PROFILE_MODULE = 'accounts.UserProfile'
+
+When a user profile model has been defined and specified in this manner, each
+:class:`~django.contrib.auth.models.User` object will have a method --
+:class:`~django.contrib.auth.models.User.get_profile()` -- which returns the
+instance of the user profile model associated with that
+:class:`~django.contrib.auth.models.User`.
+
+The method :class:`~django.contrib.auth.models.User.get_profile()`
+does not create the profile, if it does not exist. You need to
+register a handler for the signal
+:attr:`django.db.models.signals.post_save` on the User model, and, in
+the handler, if created=True, create the associated user profile.
+
+For more information, see `Chapter 12 of the Django book`_.
+
+.. _Chapter 12 of the Django book: http://www.djangobook.com/en/1.0/chapter12/#cn222
+
+Authentication in Web requests
+==============================
+
+Until now, this document has dealt with the low-level APIs for manipulating
+authentication-related objects. On a higher level, Django can hook this
+authentication framework into its system of
+:class:`request objects <django.http.HttpRequest>`.
+
+First, install the
+:class:`~django.contrib.sessions.middleware.SessionMiddleware` and
+:class:`~django.contrib.auth.middleware.AuthenticationMiddleware`
+middlewares by adding them to your :setting:`MIDDLEWARE_CLASSES` setting. See
+the :doc:`session documentation </topics/http/sessions>` for more information.
+
+Once you have those middlewares installed, you'll be able to access
+:attr:`request.user <django.http.HttpRequest.user>` in views.
+:attr:`request.user <django.http.HttpRequest.user>` will give you a
+:class:`~django.contrib.auth.models.User` object representing the currently
+logged-in user. If a user isn't currently logged in,
+:attr:`request.user <django.http.HttpRequest.user>` will be set to an instance
+of :class:`~django.contrib.auth.models.AnonymousUser` (see the previous
+section). You can tell them apart with
+:meth:`~django.contrib.auth.models.User.is_authenticated()`, like so::
+
+    if request.user.is_authenticated():
+        # Do something for authenticated users.
+    else:
+        # Do something for anonymous users.
+
+.. _how-to-log-a-user-in:
+
+How to log a user in
+--------------------
+
+Django provides two functions in :mod:`django.contrib.auth`:
+:func:`~django.contrib.auth.authenticate()` and
+:func:`~django.contrib.auth.login()`.
+
+.. function:: authenticate()
+
+    To authenticate a given username and password, use
+    :func:`~django.contrib.auth.authenticate()`. It takes two keyword
+    arguments, ``username`` and ``password``, and it returns a
+    :class:`~django.contrib.auth.models.User` object if the password is valid
+    for the given username. If the password is invalid,
+    :func:`~django.contrib.auth.authenticate()` returns ``None``. Example::
+
+        from django.contrib.auth import authenticate
+        user = authenticate(username='john', password='secret')
+        if user is not None:
+            if user.is_active:
+                print "You provided a correct username and password!"
+            else:
+                print "Your account has been disabled!"
+        else:
+            print "Your username and password were incorrect."
+
+.. function:: login()
+
+    To log a user in, in a view, use :func:`~django.contrib.auth.login()`. It
+    takes an :class:`~django.http.HttpRequest` object and a
+    :class:`~django.contrib.auth.models.User` object.
+    :func:`~django.contrib.auth.login()` saves the user's ID in the session,
+    using Django's session framework, so, as mentioned above, you'll need to
+    make sure to have the session middleware installed.
+
+    This example shows how you might use both
+    :func:`~django.contrib.auth.authenticate()` and
+    :func:`~django.contrib.auth.login()`::
+
+        from django.contrib.auth import authenticate, login
+
+        def my_view(request):
+            username = request.POST['username']
+            password = request.POST['password']
+            user = authenticate(username=username, password=password)
+            if user is not None:
+                if user.is_active:
+                    login(request, user)
+                    # Redirect to a success page.
+                else:
+                    # Return a 'disabled account' error message
+            else:
+                # Return an 'invalid login' error message.
+
+.. admonition:: Calling ``authenticate()`` first
+
+    When you're manually logging a user in, you *must* call
+    :func:`~django.contrib.auth.authenticate()` before you call
+    :func:`~django.contrib.auth.login()`.
+    :func:`~django.contrib.auth.authenticate()`
+    sets an attribute on the :class:`~django.contrib.auth.models.User` noting
+    which authentication backend successfully authenticated that user (see the
+    `backends documentation`_ for details), and this information is needed
+    later during the login process.
+
+.. _backends documentation: #other-authentication-sources
+
+Manually checking a user's password
+-----------------------------------
+
+.. currentmodule:: django.contrib.auth.models
+
+.. function:: check_password()
+
+    If you'd like to manually authenticate a user by comparing a plain-text
+    password to the hashed password in the database, use the convenience
+    function :func:`django.contrib.auth.models.check_password`. It takes two
+    arguments: the plain-text password to check, and the full value of a user's
+    ``password`` field in the database to check against, and returns ``True``
+    if they match, ``False`` otherwise.
+
+How to log a user out
+---------------------
+
+.. currentmodule:: django.contrib.auth
+
+.. function:: logout()
+
+    To log out a user who has been logged in via
+    :func:`django.contrib.auth.login()`, use
+    :func:`django.contrib.auth.logout()` within your view. It takes an
+    :class:`~django.http.HttpRequest` object and has no return value.
+    Example::
+
+        from django.contrib.auth import logout
+
+        def logout_view(request):
+            logout(request)
+            # Redirect to a success page.
+
+    Note that :func:`~django.contrib.auth.logout()` doesn't throw any errors if
+    the user wasn't logged in.
+
+    When you call :func:`~django.contrib.auth.logout()`, the session data for
+    the current request is completely cleaned out. All existing data is
+    removed. This is to prevent another person from using the same Web browser
+    to log in and have access to the previous user's session data. If you want
+    to put anything into the session that will be available to the user
+    immediately after logging out, do that *after* calling
+    :func:`django.contrib.auth.logout()`.
+
+.. _topics-auth-signals:
+
+Login and logout signals
+------------------------
+
+.. versionadded:: 1.3
+
+The auth framework uses two :doc:`signals </topics/signals>` that can be used
+for notification when a user logs in or out.
+
+.. data:: django.contrib.auth.signals.user_logged_in
+
+Sent when a user logs in successfully.
+
+Arguments sent with this signal:
+
+    ``sender``
+        As above: the class of the user that just logged in.
+
+    ``request``
+        The current :class:`~django.http.HttpRequest` instance.
+
+    ``user``
+        The user instance that just logged in.
+
+.. data:: django.contrib.auth.signals.user_logged_out
+
+Sent when the logout method is called.
+
+    ``sender``
+        As above: the class of the user that just logged out or ``None``
+        if the user was not authenticated.
+
+    ``request``
+        The current :class:`~django.http.HttpRequest` instance.
+
+    ``user``
+        The user instance that just logged out or ``None`` if the
+        user was not authenticated.
+
+Limiting access to logged-in users
+----------------------------------
+
+The raw way
+~~~~~~~~~~~
+
+The simple, raw way to limit access to pages is to check
+:meth:`request.user.is_authenticated()
+<django.contrib.auth.models.User.is_authenticated()>` and either redirect to a
+login page::
+
+    from django.http import HttpResponseRedirect
+
+    def my_view(request):
+        if not request.user.is_authenticated():
+            return HttpResponseRedirect('/login/?next=%s' % request.path)
+        # ...
+
+...or display an error message::
+
+    def my_view(request):
+        if not request.user.is_authenticated():
+            return render_to_response('myapp/login_error.html')
+        # ...
+
+The login_required decorator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. function:: decorators.login_required([redirect_field_name=REDIRECT_FIELD_NAME, login_url=None])
+
+    As a shortcut, you can use the convenient
+    :func:`~django.contrib.auth.decorators.login_required` decorator::
+
+        from django.contrib.auth.decorators import login_required
+
+        @login_required
+        def my_view(request):
+            ...
+
+    :func:`~django.contrib.auth.decorators.login_required` does the following:
+
+    * If the user isn't logged in, redirect to
+      :setting:`settings.LOGIN_URL <LOGIN_URL>`, passing the current absolute
+      path in the query string. Example: ``/accounts/login/?next=/polls/3/``.
+
+    * If the user is logged in, execute the view normally. The view code is
+      free to assume the user is logged in.
+
+    By default, the path that the user should be redirected to upon
+    successful authentication is stored in a query string parameter called
+    ``"next"``. If you would prefer to use a different name for this parameter,
+    :func:`~django.contrib.auth.decorators.login_required` takes an
+    optional ``redirect_field_name`` parameter::
+
+        from django.contrib.auth.decorators import login_required
+
+        @login_required(redirect_field_name='my_redirect_field')
+        def my_view(request):
+            ...
+
+    Note that if you provide a value to ``redirect_field_name``, you will most
+    likely need to customize your login template as well, since the template
+    context variable which stores the redirect path will use the value of
+    ``redirect_field_name`` as it's key rather than ``"next"`` (the default).
+
+    .. versionadded:: 1.3
+
+    :func:`~django.contrib.auth.decorators.login_required` also takes an
+    optional ``login_url`` parameter. Example::
+
+        from django.contrib.auth.decorators import login_required
+
+        @login_required(login_url='/accounts/login/')
+        def my_view(request):
+            ...
+
+    Note that if you don't specify the ``login_url`` parameter, you'll need to map
+    the appropriate Django view to :setting:`settings.LOGIN_URL <LOGIN_URL>`. For
+    example, using the defaults, add the following line to your URLconf::
+
+        (r'^accounts/login/$', 'django.contrib.auth.views.login'),
+
+.. function:: views.login(request, [template_name, redirect_field_name, authentication_form])
+
+    Here's what ``django.contrib.auth.views.login`` does:
+
+        * If called via ``GET``, it displays a login form that POSTs to the
+          same URL. More on this in a bit.
+
+        * If called via ``POST``, it tries to log the user in. If login is
+          successful, the view redirects to the URL specified in ``next``. If
+          ``next`` isn't provided, it redirects to
+          :setting:`settings.LOGIN_REDIRECT_URL <LOGIN_REDIRECT_URL>` (which
+          defaults to ``/accounts/profile/``). If login isn't successful, it
+          redisplays the login form.
+
+    It's your responsibility to provide the login form in a template called
+    ``registration/login.html`` by default. This template gets passed four
+    template context variables:
+
+        * ``form``: A :class:`~django.forms.Form` object representing the login
+          form. See the :doc:`forms documentation </topics/forms/index>` for
+          more on ``Form`` objects.
+
+        * ``next``: The URL to redirect to after successful login. This may
+          contain a query string, too.
+
+        * ``site``: The current :class:`~django.contrib.sites.models.Site`,
+          according to the :setting:`SITE_ID` setting. If you don't have the
+          site framework installed, this will be set to an instance of
+          :class:`~django.contrib.sites.models.RequestSite`, which derives the
+          site name and domain from the current
+          :class:`~django.http.HttpRequest`.
+
+        * ``site_name``: An alias for ``site.name``. If you don't have the site
+          framework installed, this will be set to the value of
+          :attr:`request.META['SERVER_NAME'] <django.http.HttpRequest.META>`.
+          For more on sites, see :doc:`/ref/contrib/sites`.
+
+    If you'd prefer not to call the template :file:`registration/login.html`,
+    you can pass the ``template_name`` parameter via the extra arguments to
+    the view in your URLconf. For example, this URLconf line would use
+    :file:`myapp/login.html` instead::
+
+        (r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'myapp/login.html'}),
+
+    You can also specify the name of the ``GET`` field which contains the URL
+    to redirect to after login by passing ``redirect_field_name`` to the view.
+    By default, the field is called ``next``.
+
+    Here's a sample :file:`registration/login.html` template you can use as a
+    starting point. It assumes you have a :file:`base.html` template that
+    defines a ``content`` block:
+
+    .. code-block:: html+django
+
+        {% extends "base.html" %}
+        {% load url from future %}
+
+        {% block content %}
+
+        {% if form.errors %}
+        <p>Your username and password didn't match. Please try again.</p>
+        {% endif %}
+
+        <form method="post" action="{% url 'django.contrib.auth.views.login' %}">
+        {% csrf_token %}
+        <table>
+        <tr>
+            <td>{{ form.username.label_tag }}</td>
+            <td>{{ form.username }}</td>
+        </tr>
+        <tr>
+            <td>{{ form.password.label_tag }}</td>
+            <td>{{ form.password }}</td>
+        </tr>
+        </table>
+
+        <input type="submit" value="login" />
+        <input type="hidden" name="next" value="{{ next }}" />
+        </form>
+
+        {% 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
+    accept a ``request`` keyword argument in its ``__init__`` method, and
+    provide a ``get_user`` method which returns the authenticated user object
+    (this method is only ever called after successful form validation).
+
+    .. _forms documentation: ../forms/
+    .. _site framework docs: ../sites/
+
+    .. versionadded:: 1.4
+
+    The :func:`~views.login` view and the :ref:`other-built-in-views` now all
+    return a :class:`~django.template.response.TemplateResponse` instance,
+    which allows you to easily customize the response data before rendering.
+    For more details, see the
+    :doc:`TemplateResponse documentation </ref/template-response>`.
+
+.. _other-built-in-views:
+
+Other built-in views
+--------------------
+
+.. module:: django.contrib.auth.views
+
+In addition to the :func:`~views.login` view, the authentication system
+includes a few other useful built-in views located in
+:mod:`django.contrib.auth.views`:
+
+.. function:: logout(request, [next_page, template_name, redirect_field_name])
+
+    Logs a user out.
+
+    **Optional arguments:**
+
+        * ``next_page``: The URL to redirect to after logout.
+
+        * ``template_name``: The full name of a template to display after
+          logging the user out. This will default to
+          :file:`registration/logged_out.html` if no argument is supplied.
+
+        * ``redirect_field_name``: The name of a ``GET`` field containing the
+          URL to redirect to after log out. Overrides ``next_page`` if the given
+          ``GET`` parameter is passed.
+
+    **Template context:**
+
+        * ``title``: The string "Logged out", localized.
+
+.. function:: logout_then_login(request[, login_url])
+
+    Logs a user out, then redirects to the login page.
+
+    **Optional arguments:**
+
+        * ``login_url``: The URL of the login page to redirect to. This will
+          default to :setting:`settings.LOGIN_URL <LOGIN_URL>` if not supplied.
+
+.. function:: password_change(request[, template_name, post_change_redirect, password_change_form])
+
+    Allows a user to change their password.
+
+    **Optional arguments:**
+
+        * ``template_name``: The full name of a template to use for
+          displaying the password change form. This will default to
+          :file:`registration/password_change_form.html` if not supplied.
+
+        * ``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.
+
+
+    **Template context:**
+
+        * ``form``: The password change form.
+
+.. function:: password_change_done(request[, template_name])
+
+    The page shown after a user has changed their password.
+
+    **Optional arguments:**
+
+        * ``template_name``: The full name of a template to use. This will
+          default to :file:`registration/password_change_done.html` if not
+          supplied.
+
+.. function:: password_reset(request[, is_admin_site, template_name, email_template_name, password_reset_form, token_generator, post_reset_redirect, from_email])
+
+    Allows a user to reset their password by generating a one-time use link
+    that can be used to reset the password, and sending that link to the
+    user's registered email address.
+
+    .. versionchanged:: 1.3
+        The ``from_email`` argument was added.
+
+    **Optional arguments:**
+
+        * ``template_name``: The full name of a template to use for
+          displaying the password reset form. This will default to
+          :file:`registration/password_reset_form.html` if not supplied.
+
+        * ``email_template_name``: The full name of a template to use for
+          generating the email with the new password. This will default to
+          :file:`registration/password_reset_email.html` if not supplied.
+
+        * ``password_reset_form``: Form that will be used to set the password.
+          Defaults to :class:`~django.contrib.auth.forms.PasswordResetForm`.
+
+        * ``token_generator``: Instance of the class to check the password. This
+          will default to ``default_token_generator``, it's an instance of
+          ``django.contrib.auth.tokens.PasswordResetTokenGenerator``.
+
+        * ``post_reset_redirect``: The URL to redirect to after a successful
+          password change.
+
+        * ``from_email``: A valid email address. By default Django uses
+          the :setting:`DEFAULT_FROM_EMAIL`.
+
+    **Template context:**
+
+        * ``form``: The form for resetting the user's password.
+
+.. function:: password_reset_done(request[, template_name])
+
+    The page shown after a user has reset their password.
+
+    **Optional arguments:**
+
+        * ``template_name``: The full name of a template to use. This will
+          default to :file:`registration/password_reset_done.html` if not
+          supplied.
+
+.. function:: password_reset_confirm(request[, uidb36, token, template_name, token_generator, set_password_form, post_reset_redirect])
+
+    Presents a form for entering a new password.
+
+    **Optional arguments:**
+
+        * ``uidb36``: The user's id encoded in base 36. This will default to
+          ``None``.
+        * ``token``: Token to check that the password is valid. This will default to ``None``.
+        * ``template_name``: The full name of a template to display the confirm
+          password view. Default value is :file:`registration/password_reset_confirm.html`.
+        * ``token_generator``: Instance of the class to check the password. This
+          will default to ``default_token_generator``, it's an instance of
+          ``django.contrib.auth.tokens.PasswordResetTokenGenerator``.
+        * ``set_password_form``: Form that will be used to set the password.
+          This will default to ``SetPasswordForm``.
+        * ``post_reset_redirect``: URL to redirect after the password reset
+          done. This will default to ``None``.
+
+.. function:: password_reset_complete(request[,template_name])
+
+   Presents a view which informs the user that the password has been
+   successfully changed.
+
+   **Optional arguments:**
+
+       * ``template_name``: The full name of a template to display the view.
+         This will default to :file:`registration/password_reset_complete.html`.
+
+Helper functions
+----------------
+
+.. currentmodule:: django.contrib.auth.views
+
+.. function:: redirect_to_login(next[, login_url, redirect_field_name])
+
+    Redirects to the login page, and then back to another URL after a
+    successful login.
+
+    **Required arguments:**
+
+        * ``next``: The URL to redirect to after a successful login.
+
+    **Optional arguments:**
+
+        * ``login_url``: The URL of the login page to redirect to. This will
+          default to :setting:`settings.LOGIN_URL <LOGIN_URL>` if not supplied.
+
+        * ``redirect_field_name``: The name of a ``GET`` field containing the
+          URL to redirect to after log out. Overrides ``next`` if the given
+          ``GET`` parameter is passed.
+
+Built-in forms
+--------------
+
+.. module:: django.contrib.auth.forms
+
+If you don't want to use the built-in views, but want the convenience of not
+having to write forms for this functionality, the authentication system
+provides several built-in forms located in :mod:`django.contrib.auth.forms`:
+
+.. class:: AdminPasswordChangeForm
+
+    A form used in the admin interface to change a user's password.
+
+.. class:: AuthenticationForm
+
+    A form for logging a user in.
+
+.. class:: PasswordChangeForm
+
+    A form for allowing a user to change their password.
+
+.. class:: PasswordResetForm
+
+    A form for generating and emailing a one-time use link to reset a
+    user's password.
+
+.. class:: SetPasswordForm
+
+    A form that lets a user change his/her password without entering the old
+    password.
+
+.. class:: UserChangeForm
+
+    A form used in the admin interface to change a user's information and
+    permissions.
+
+.. class:: UserCreationForm
+
+    A form for creating a new user.
+
+Limiting access to logged-in users that pass a test
+---------------------------------------------------
+
+.. currentmodule:: django.contrib.auth.decorators
+
+To limit access based on certain permissions or some other test, you'd do
+essentially the same thing as described in the previous section.
+
+The simple way is to run your test on :attr:`request.user
+<django.http.HttpRequest.user>` in the view directly. For example, this view
+checks to make sure the user is logged in and has the permission
+``polls.can_vote``::
+
+    def my_view(request):
+        if not request.user.has_perm('polls.can_vote'):
+            return HttpResponse("You can't vote in this poll.")
+        # ...
+
+.. function:: user_passes_test()
+
+    As a shortcut, you can use the convenient ``user_passes_test`` decorator::
+
+        from django.contrib.auth.decorators import user_passes_test
+
+        @user_passes_test(lambda u: u.has_perm('polls.can_vote'))
+        def my_view(request):
+            ...
+
+    We're using this particular test as a relatively simple example. However,
+    if you just want to test whether a permission is available to a user, you
+    can use the :func:`~django.contrib.auth.decorators.permission_required()`
+    decorator, described later in this document.
+
+    :func:`~django.contrib.auth.decorators.user_passes_test` takes a required
+    argument: a callable that takes a
+    :class:`~django.contrib.auth.models.User` object and returns ``True`` if
+    the user is allowed to view the page. Note that
+    :func:`~django.contrib.auth.decorators.user_passes_test` does not
+    automatically check that the :class:`~django.contrib.auth.models.User` is
+    not anonymous.
+
+    :func:`~django.contrib.auth.decorators.user_passes_test()` takes an
+    optional ``login_url`` argument, which lets you specify the URL for your
+    login page (:setting:`settings.LOGIN_URL <LOGIN_URL>` by default).
+
+    For example::
+
+        from django.contrib.auth.decorators import user_passes_test
+
+        @user_passes_test(lambda u: u.has_perm('polls.can_vote'), login_url='/login/')
+        def my_view(request):
+            ...
+
+The permission_required decorator
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. function:: permission_required()
+
+    It's a relatively common task to check whether a user has a particular
+    permission. For that reason, Django provides a shortcut for that case: the
+    :func:`~django.contrib.auth.decorators.permission_required()` decorator.
+    Using this decorator, the earlier example can be written as::
+
+        from django.contrib.auth.decorators import permission_required
+
+        @permission_required('polls.can_vote')
+        def my_view(request):
+            ...
+
+    As for the :meth:`User.has_perm` method, permission names take the form
+    ``"<app label>.<permission codename>"`` (i.e. ``polls.can_vote`` for a
+    permission on a model in the ``polls`` application).
+
+    Note that :func:`~django.contrib.auth.decorators.permission_required()`
+    also takes an optional ``login_url`` parameter. Example::
+
+        from django.contrib.auth.decorators import permission_required
+
+        @permission_required('polls.can_vote', login_url='/loginpage/')
+        def my_view(request):
+            ...
+
+    As in the :func:`~decorators.login_required` decorator, ``login_url``
+    defaults to :setting:`settings.LOGIN_URL <LOGIN_URL>`.
+
+.. currentmodule:: django.contrib.auth
+
+Limiting access to generic views
+--------------------------------
+
+To limit access to a :doc:`generic view </ref/generic-views>`, write a thin
+wrapper around the view, and point your URLconf to your wrapper instead of the
+generic view itself. For example::
+
+    from django.views.generic.date_based import object_detail
+
+    @login_required
+    def limited_object_detail(*args, **kwargs):
+        return object_detail(*args, **kwargs)
+
+.. _permissions:
+
+Permissions
+===========
+
+Django comes with a simple permissions system. It provides a way to assign
+permissions to specific users and groups of users.
+
+It's used by the Django admin site, but you're welcome to use it in your own
+code.
+
+The Django admin site uses permissions as follows:
+
+    * Access to view the "add" form and add an object is limited to users with
+      the "add" permission for that type of object.
+    * Access to view the change list, view the "change" form and change an
+      object is limited to users with the "change" permission for that type of
+      object.
+    * 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.
+
+Default permissions
+-------------------
+
+When ``django.contrib.auth`` is listed in your :setting:`INSTALLED_APPS`
+setting, it will ensure that three default permissions -- add, change and
+delete -- are created for each Django model defined in one of your installed
+applications.
+
+These permissions will be created when you run :djadmin:`manage.py syncdb
+<syncdb>`; the first time you run ``syncdb`` after adding
+``django.contrib.auth`` to :setting:`INSTALLED_APPS`, the default permissions
+will be created for all previously-installed models, as well as for any new
+models being installed at that time. Afterward, it will create default
+permissions for new models each time you run :djadmin:`manage.py syncdb
+<syncdb>`.
+
+Assuming you have an application with an
+:attr:`~django.db.models.Options.app_label` ``foo`` and a model named ``Bar``,
+to test for basic permissions you should use:
+
+    * add: ``user.has_perm('foo.add_bar')``
+    * change: ``user.has_perm('foo.change_bar')``
+    * delete: ``user.has_perm('foo.delete_bar')``
+
+.. _custom-permissions:
+
+Custom permissions
+------------------
+
+To create custom permissions for a given model object, use the ``permissions``
+:ref:`model Meta attribute <meta-options>`.
+
+This example Task model creates three custom permissions, i.e., actions users
+can or cannot do with Task instances, specific to your application::
+
+    class Task(models.Model):
+        ...
+        class Meta:
+            permissions = (
+                ("can_view", "Can see available tasks"),
+                ("can_change_status", "Can change the status of tasks"),
+                ("can_close", "Can remove a task by setting its status as closed"),
+            )
+
+The only thing this does is create those extra permissions when you run
+:djadmin:`manage.py syncdb <syncdb>`. Your code is in charge of checking the
+value of these permissions when an user is trying to access the functionality
+provided by the application (viewing tasks, changing the status of tasks,
+closing tasks.)
+
+API reference
+-------------
+
+.. currentmodule:: django.contrib.auth.models
+
+.. class:: Permission
+
+    Just like users, permissions are implemented in a Django model that lives
+    in `django/contrib/auth/models.py`_.
+
+.. _django/contrib/auth/models.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py
+
+Fields
+~~~~~~
+
+:class:`~django.contrib.auth.models.Permission` objects have the following
+fields:
+
+.. attribute:: Permission.name
+
+    Required. 50 characters or fewer. Example: ``'Can vote'``.
+
+.. attribute:: Permission.content_type
+
+    Required. A reference to the ``django_content_type`` database table, which
+    contains a record for each installed Django model.
+
+.. attribute:: Permission.codename
+
+    Required. 100 characters or fewer. Example: ``'can_vote'``.
+
+Methods
+~~~~~~~
+
+:class:`~django.contrib.auth.models.Permission` objects have the standard
+data-access methods like any other :doc:`Django model </ref/models/instances>`.
+
+.. currentmodule:: django.contrib.auth
+
+Authentication data in templates
+================================
+
+The currently logged-in user and his/her permissions are made available in the
+:doc:`template context </ref/templates/api>` when you use
+:class:`~django.template.context.RequestContext`.
+
+.. admonition:: Technicality
+
+   Technically, these variables are only made available in the template context
+   if you use :class:`~django.template.context.RequestContext` *and* your
+   :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting contains
+   ``"django.contrib.auth.context_processors.auth"``, which is default. For
+   more, see the :ref:`RequestContext docs <subclassing-context-requestcontext>`.
+
+Users
+-----
+
+When rendering a template :class:`~django.template.context.RequestContext`, the
+currently logged-in user, either a  :class:`~django.contrib.auth.models.User`
+instance or an :class:`~django.contrib.auth.models.AnonymousUser` instance, is
+stored in the template variable ``{{ user }}``:
+
+.. code-block:: html+django
+
+    {% if user.is_authenticated %}
+        <p>Welcome, {{ user.username }}. Thanks for logging in.</p>
+    {% else %}
+        <p>Welcome, new user. Please log in.</p>
+    {% endif %}
+
+This template context variable is not available if a ``RequestContext`` is not
+being used.
+
+Permissions
+-----------
+
+The currently logged-in user's permissions are stored in the template variable
+``{{ perms }}``. This is an instance of
+:class:`django.contrib.auth.context_processors.PermWrapper`, which is a
+template-friendly proxy of permissions.
+
+.. versionchanged:: 1.3
+    Prior to version 1.3, ``PermWrapper`` was located in
+    ``django.contrib.auth.context_processors``.
+
+In the ``{{ perms }}`` object, single-attribute lookup is a proxy to
+:meth:`User.has_module_perms <django.contrib.auth.models.User.has_module_perms>`.
+This example would display ``True`` if the logged-in user had any permissions
+in the ``foo`` app::
+
+    {{ perms.foo }}
+
+Two-level-attribute lookup is a proxy to
+:meth:`User.has_perm <django.contrib.auth.models.User.has_perm>`. This example
+would display ``True`` if the logged-in user had the permission
+``foo.can_vote``::
+
+    {{ perms.foo.can_vote }}
+
+Thus, you can check permissions in template ``{% if %}`` statements:
+
+.. code-block:: html+django
+
+    {% if perms.foo %}
+        <p>You have permission to do something in the foo app.</p>
+        {% if perms.foo.can_vote %}
+            <p>You can vote!</p>
+        {% endif %}
+        {% if perms.foo.can_drive %}
+            <p>You can drive!</p>
+        {% endif %}
+    {% else %}
+        <p>You don't have permission to do anything in the foo app.</p>
+    {% endif %}
+
+Groups
+======
+
+Groups are a generic way of categorizing users so you can apply permissions, or
+some other label, to those users. A user can belong to any number of groups.
+
+A user in a group automatically has the permissions granted to that group. For
+example, if the group ``Site editors`` has the permission
+``can_edit_home_page``, any user in that group will have that permission.
+
+Beyond permissions, groups are a convenient way to categorize users to give
+them some label, or extended functionality. For example, you could create a
+group ``'Special users'``, and you could write code that could, say, give them
+access to a members-only portion of your site, or send them members-only email
+messages.
+
+.. _authentication-backends:
+
+Other authentication sources
+============================
+
+The authentication that comes with Django is good enough for most common cases,
+but you may have the need to hook into another authentication source -- that
+is, another source of usernames and passwords or authentication methods.
+
+For example, your company may already have an LDAP setup that stores a username
+and password for every employee. It'd be a hassle for both the network
+administrator and the users themselves if users had separate accounts in LDAP
+and the Django-based applications.
+
+So, to handle situations like this, the Django authentication system lets you
+plug in other authentication sources. You can override Django's default
+database-based scheme, or you can use the default system in tandem with other
+systems.
+
+See the :doc:`authentication backend reference </ref/authbackends>`
+for information on the authentication backends included with Django.
+
+Specifying authentication backends
+----------------------------------
+
+Behind the scenes, Django maintains a list of "authentication backends" that it
+checks for authentication. When somebody calls
+:func:`django.contrib.auth.authenticate()` -- as described in :ref:`How to log
+a user in <how-to-log-a-user-in>` above -- Django tries authenticating across
+all of its authentication backends. If the first authentication method fails,
+Django tries the second one, and so on, until all backends have been attempted.
+
+The list of authentication backends to use is specified in the
+:setting:`AUTHENTICATION_BACKENDS` setting. This should be a tuple of Python
+path names that point to Python classes that know how to authenticate. These
+classes can be anywhere on your Python path.
+
+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.
+
+The order of :setting:`AUTHENTICATION_BACKENDS` matters, so if the same
+username and password is valid in multiple backends, Django will stop
+processing at the first positive match.
+
+.. note::
+
+    Once a user has authenticated, Django stores which backend was used to
+    authenticate the user in the user's session, and re-uses the same backend
+    for subsequent authentication attempts for that user. This effectively means
+    that authentication sources are cached, so if you change
+    :setting:`AUTHENTICATION_BACKENDS`, you'll need to clear out session data if
+    you need to force users to re-authenticate using different methods. A simple
+    way to do that is simply to execute ``Session.objects.all().delete()``.
+
+Writing an authentication backend
+---------------------------------
+
+An authentication backend is a class that implements two methods:
+``get_user(user_id)`` and ``authenticate(**credentials)``.
+
+The ``get_user`` method takes a ``user_id`` -- which could be a username,
+database ID or whatever -- and returns a ``User`` object.
+
+The ``authenticate`` method takes credentials as keyword arguments. Most of
+the time, it'll just look like this::
+
+    class MyBackend:
+        def authenticate(self, username=None, password=None):
+            # Check the username/password and return a User.
+
+But it could also authenticate a token, like so::
+
+    class MyBackend:
+        def authenticate(self, token=None):
+            # Check the token and return a User.
+
+Either way, ``authenticate`` should check the credentials it gets, and it
+should return a ``User`` object that matches those credentials, if the
+credentials are valid. If they're not valid, it should return ``None``.
+
+The Django admin system is tightly coupled to the Django ``User`` object
+described at the beginning of this document. For now, the best way to deal with
+this is to create a Django ``User`` object for each user that exists for your
+backend (e.g., in your LDAP directory, your external SQL database, etc.) You
+can either write a script to do this in advance, or your ``authenticate``
+method can do it the first time a user logs in.
+
+Here's an example backend that authenticates against a username and password
+variable defined in your ``settings.py`` file and creates a Django ``User``
+object the first time a user authenticates::
+
+    from django.conf import settings
+    from django.contrib.auth.models import User, check_password
+
+    class SettingsBackend:
+        """
+        Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.
+
+        Use the login name, and a hash of the password. For example:
+
+        ADMIN_LOGIN = 'admin'
+        ADMIN_PASSWORD = 'sha1$4e987$afbcf42e21bd417fb71db8c66b321e9fc33051de'
+        """
+
+        supports_object_permissions = False
+        supports_anonymous_user = False
+        supports_inactive_user = False
+
+        def authenticate(self, username=None, password=None):
+            login_valid = (settings.ADMIN_LOGIN == username)
+            pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
+            if login_valid and pwd_valid:
+                try:
+                    user = User.objects.get(username=username)
+                except User.DoesNotExist:
+                    # Create a new user. Note that we can set password
+                    # to anything, because it won't be checked; the password
+                    # from settings.py will.
+                    user = User(username=username, password='get from settings.py')
+                    user.is_staff = True
+                    user.is_superuser = True
+                    user.save()
+                return user
+            return None
+
+        def get_user(self, user_id):
+            try:
+                return User.objects.get(pk=user_id)
+            except User.DoesNotExist:
+                return None
+
+Handling authorization in custom backends
+-----------------------------------------
+
+Custom auth backends can provide their own permissions.
+
+The user model will delegate permission lookup functions
+(:meth:`~django.contrib.auth.models.User.get_group_permissions()`,
+:meth:`~django.contrib.auth.models.User.get_all_permissions()`,
+:meth:`~django.contrib.auth.models.User.has_perm()`, and
+:meth:`~django.contrib.auth.models.User.has_module_perms()`) to any
+authentication backend that implements these functions.
+
+The permissions given to the user will be the superset of all permissions
+returned by all backends. That is, Django grants a permission to a user that
+any one backend grants.
+
+The simple backend above could implement permissions for the magic admin
+fairly simply::
+
+    class SettingsBackend:
+
+        # ...
+
+        def has_perm(self, user_obj, perm):
+            if user_obj.username == settings.ADMIN_LOGIN:
+                return True
+            else:
+                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.
+
+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.
+
+.. _django/contrib/auth/backends.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/backends.py
+
+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
+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.
+
+To enable this in your own backend, you must set the class attribute
+``supports_anonymous_user`` to ``True``. (This precaution is to maintain
+compatibility with backends that assume that all user objects are actual
+instances of the :class:`django.contrib.auth.models.User` class). With this
+in place, :class:`django.contrib.auth.models.AnonymousUser` will delegate all
+the relevant permission methods to the authentication backends.
+
+A nonexistent ``supports_anonymous_user`` attribute will raise a hidden
+``PendingDeprecationWarning`` if used in Django 1.2. In Django 1.3, this
+warning will be upgraded to a ``DeprecationWarning``, which will be displayed
+loudly. Additionally ``supports_anonymous_user`` will be set to ``False``.
+Django 1.4 will assume that every backend supports anonymous users being
+passed to the authorization methods.
+
+Authorization for inactive users
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. versionadded:: 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
+authenticated users do not.
+
+To enable this on your own backend, you must set the class attribute
+``supports_inactive_user`` to ``True``.
+
+A nonexisting ``supports_inactive_user`` attribute will raise a
+``PendingDeprecationWarning`` if used in Django 1.3. In Django 1.4, this
+warning will be updated to a ``DeprecationWarning`` which will be displayed
+loudly. Additionally ``supports_inactive_user`` will be set to ``False``.
+Django 1.5 will assume that every backend supports inactive users being
+passed to the authorization 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).
+
+To enable object permissions in your own
+:doc:`authentication backend </ref/authbackends>` you'll just have
+to allow passing an ``obj`` parameter to the permission methods and set the
+``supports_object_permissions`` class attribute to ``True``.
+
+A nonexistent ``supports_object_permissions`` will raise a hidden
+``PendingDeprecationWarning`` if used in Django 1.2. In Django 1.3, this
+warning will be upgraded to a ``DeprecationWarning``, which will be displayed
+loudly. Additionally ``supports_object_permissions`` will be set to ``False``.
+Django 1.4 will assume that every backend supports object permissions and
+won't check for the existence of ``supports_object_permissions``, which
+means not supporting ``obj`` as a parameter will raise a ``TypeError``.
+========================
+Django's cache framework
+========================
+
+A fundamental trade-off in dynamic Web sites is, well, they're dynamic. Each
+time a user requests a page, the Web server makes all sorts of calculations --
+from database queries to template rendering to business logic -- to create the
+page that your site's visitor sees. This is a lot more expensive, from a
+processing-overhead perspective, than your standard
+read-a-file-off-the-filesystem server arrangement.
+
+For most Web applications, this overhead isn't a big deal. Most Web
+applications aren't washingtonpost.com or slashdot.org; they're simply small-
+to medium-sized sites with so-so traffic. But for medium- to high-traffic
+sites, it's essential to cut as much overhead as possible.
+
+That's where caching comes in.
+
+To cache something is to save the result of an expensive calculation so that
+you don't have to perform the calculation next time. Here's some pseudocode
+explaining how this would work for a dynamically generated Web page::
+
+    given a URL, try finding that page in the cache
+    if the page is in the cache:
+        return the cached page
+    else:
+        generate the page
+        save the generated page in the cache (for next time)
+        return the generated page
+
+Django comes with a robust cache system that lets you save dynamic pages so
+they don't have to be calculated for each request. For convenience, Django
+offers different levels of cache granularity: You can cache the output of
+specific views, you can cache only the pieces that are difficult to produce,
+or you can cache your entire site.
+
+Django also works well with "upstream" caches, such as `Squid
+<http://www.squid-cache.org>`_ and browser-based caches. These are the types of
+caches that you don't directly control but to which you can provide hints (via
+HTTP headers) about which parts of your site should be cached, and how.
+
+Setting up the cache
+====================
+
+The cache system requires a small amount of setup. Namely, you have to tell it
+where your cached data should live -- whether in a database, on the filesystem
+or directly in memory. This is an important decision that affects your cache's
+performance; yes, some cache types are faster than others.
+
+Your cache preference goes in the :setting:`CACHES` setting in your
+settings file. Here's an explanation of all available values for
+:setting:`CACHES`.
+
+.. versionchanged:: 1.3
+    The settings used to configure caching changed in Django 1.3. In
+    Django 1.2 and earlier, you used a single string-based
+    :setting:`CACHE_BACKEND` setting to configure caches. This has
+    been replaced with the new dictionary-based :setting:`CACHES`
+    setting.
+
+.. _memcached:
+
+Memcached
+---------
+
+By far the fastest, most efficient type of cache available to Django, Memcached
+is an entirely memory-based cache framework originally developed to handle high
+loads at LiveJournal.com and subsequently open-sourced by Danga Interactive.
+It's used by sites such as Facebook and Wikipedia to reduce database access and
+dramatically increase site performance.
+
+Memcached is available for free at http://memcached.org/. It runs as a
+daemon and is allotted a specified amount of RAM. All it does is provide a
+fast interface for adding, retrieving and deleting arbitrary data in the cache.
+All data is stored directly in memory, so there's no overhead of database or
+filesystem usage.
+
+After installing Memcached itself, you'll need to install a memcached
+binding. There are several python memcached bindings available; the
+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.
+
+To use Memcached with Django:
+
+    * Set :setting:`BACKEND <CACHES-BACKEND>` to
+      ``django.core.cache.backends.memcached.MemcachedCache`` or
+      ``django.core.cache.backends.memcached.PyLibMCCache`` (depending
+      on your chosen memcached binding)
+
+    * Set :setting:`LOCATION <CACHES-LOCATION>` to ``ip:port`` values,
+      where ``ip`` is the IP address of the Memcached daemon and
+      ``port`` is the port on which Memcached is running.
+
+In this example, Memcached is running on localhost (127.0.0.1) port 11211, using
+the ``python-memcached`` binding::
+
+    CACHES = {
+        'default': {
+            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
+            'LOCATION': '127.0.0.1:11211',
+        }
+    }
+
+One excellent feature of Memcached is its ability to share cache over multiple
+servers. This means you can run Memcached daemons on multiple machines, and the
+program will treat the group of machines as a *single* cache, without the need
+to duplicate cache values on each machine. To take advantage of this feature,
+include all server addresses in :setting:`BACKEND <CACHES-BACKEND>`, either
+separated by semicolons or as a list.
+
+In this example, the cache is shared over Memcached instances running on IP
+address 172.19.26.240 and 172.19.26.242, both on port 11211::
+
+    CACHES = {
+        'default': {
+            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
+            'LOCATION': [
+                '172.19.26.240:11211',
+                '172.19.26.242:11211',
+            ]
+        }
+    }
+
+In the following example, the cache is shared over Memcached instances running
+on the IP addresses 172.19.26.240 (port 11211), 172.19.26.242 (port 11212), and
+172.19.26.244 (port 11213)::
+
+    CACHES = {
+        'default': {
+            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
+            'LOCATION': [
+                '172.19.26.240:11211',
+                '172.19.26.242:11211',
+                '172.19.26.244:11213',
+            ]
+        }
+    }
+
+A final point about Memcached is that memory-based caching has one
+disadvantage: Because the cached data is stored in memory, the data will be
+lost if your server crashes. Clearly, memory isn't intended for permanent data
+storage, so don't rely on memory-based caching as your only data storage.
+Without a doubt, *none* of the Django caching backends should be used for
+permanent storage -- they're all intended to be solutions for caching, not
+storage -- but we point this out here because memory-based caching is
+particularly temporary.
+
+Database caching
+----------------
+
+To use a database table as your cache backend, first create a cache table in
+your database by running this command::
+
+    python manage.py createcachetable [cache_table_name]
+
+...where ``[cache_table_name]`` is the name of the database table to create.
+(This name can be whatever you want, as long as it's a valid table name that's
+not already being used in your database.) This command creates a single table
+in your database that is in the proper format that Django's database-cache
+system expects.
+
+Once you've created that database table, set your
+:setting:`BACKEND <CACHES-BACKEND>` setting to
+``"django.core.cache.backends.db.DatabaseCache"``, and
+:setting:`LOCATION <CACHES-LOCATION>` to ``tablename`` -- the name of the
+database table. In this example, the cache table's name is ``my_cache_table``::
+
+    CACHES = {
+        'default': {
+            'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
+            'LOCATION': 'my_cache_table',
+        }
+    }
+
+
+The database caching backend uses the same database as specified in your
+settings file. You can't use a different database backend for your cache table.
+
+Database caching works best if you've got a fast, well-indexed database server.
+
+Database caching and multiple databases
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you use database caching with multiple databases, you'll also need
+to set up routing instructions for your database cache table. For the
+purposes of routing, the database cache table appears as a model named
+``CacheEntry``, in an application named ``django_cache``. This model
+won't appear in the models cache, but the model details can be used
+for routing purposes.
+
+For example, the following router would direct all cache read
+operations to ``cache_slave``, and all write operations to
+``cache_master``. The cache table will only be synchronized onto
+``cache_master``::
+
+    class CacheRouter(object):
+        """A router to control all database cache operations"""
+
+        def db_for_read(self, model, **hints):
+            "All cache read operations go to the slave"
+            if model._meta.app_label in ('django_cache',):
+                return 'cache_slave'
+            return None
+
+        def db_for_write(self, model, **hints):
+            "All cache write operations go to master"
+            if model._meta.app_label in ('django_cache',):
+                return 'cache_master'
+            return None
+
+        def allow_syncdb(self, db, model):
+            "Only synchronize the cache model on master"
+            if model._meta.app_label in ('django_cache',):
+                return db == 'cache_master'
+            return None
+
+If you don't specify routing directions for the database cache model,
+the cache backend will use the ``default`` database.
+
+Of course, if you don't use the database cache backend, you don't need
+to worry about providing routing instructions for the database cache
+model.
+
+Filesystem caching
+------------------
+
+To store cached items on a filesystem, use
+``"django.core.cache.backends.filebased.FileBasedCache"`` for
+:setting:`BACKEND <CACHES-BACKEND>`. For example, to store cached data in
+``/var/tmp/django_cache``, use this setting::
+
+    CACHES = {
+        'default': {
+            'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
+            'LOCATION': '/var/tmp/django_cache',
+        }
+    }
+
+
+If you're on Windows, put the drive letter at the beginning of the path,
+like this::
+
+    CACHES = {
+        'default': {
+            'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
+            'LOCATION': 'c:/foo/bar',
+        }
+    }
+
+The directory path should be absolute -- that is, it should start at the root
+of your filesystem. It doesn't matter whether you put a slash at the end of the
+setting.
+
+Make sure the directory pointed-to by this setting exists and is readable and
+writable by the system user under which your Web server runs. Continuing the
+above example, if your server runs as the user ``apache``, make sure the
+directory ``/var/tmp/django_cache`` exists and is readable and writable by the
+user ``apache``.
+
+Each cache value will be stored as a separate file whose contents are the
+cache data saved in a serialized ("pickled") format, using Python's ``pickle``
+module. Each file's name is the cache key, escaped for safe filesystem use.
+
+Local-memory caching
+--------------------
+
+If you want the speed advantages of in-memory caching but don't have the
+capability of running Memcached, consider the local-memory cache backend. This
+cache is multi-process and thread-safe. To use it, set
+:setting:`BACKEND <CACHES-BACKEND>` to
+``"django.core.cache.backends.locmem.LocMemCache"``. For example::
+
+    CACHES = {
+        'default': {
+            'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+            'LOCATION': 'unique-snowflake'
+        }
+    }
+
+The cache :setting:`LOCATION <CACHES-LOCATION>` is used to identify individual
+memory stores. If you only have one locmem cache, you can omit the
+:setting:`LOCATION <CACHES-LOCATION>`; however, if you have more that one local
+memory cache, you will need to assign a name to at least one of them in
+order to keep them separate.
+
+Note that each process will have its own private cache instance, which means no
+cross-process caching is possible. This obviously also means the local memory
+cache isn't particularly memory-efficient, so it's probably not a good choice
+for production environments. It's nice for development.
+
+Dummy caching (for development)
+-------------------------------
+
+Finally, Django comes with a "dummy" cache that doesn't actually cache -- it
+just implements the cache interface without doing anything.
+
+This is useful if you have a production site that uses heavy-duty caching in
+various places but a development/test environment where you don't want to cache
+and don't want to have to change your code to special-case the latter. To
+activate dummy caching, set :setting:`BACKEND <CACHES-BACKEND>` like so::
+
+    CACHES = {
+        'default': {
+            'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
+        }
+    }
+
+Using a custom cache backend
+----------------------------
+
+While Django includes support for a number of cache backends out-of-the-box,
+sometimes you might want to use a customized cache backend. To use an external
+cache backend with Django, use the Python import path as the
+:setting:`BACKEND <CACHES-BACKEND>` of the :setting:`CACHES` setting, like so::
+
+    CACHES = {
+        'default': {
+            'BACKEND': 'path.to.backend',
+        }
+    }
+
+If you're building your own backend, you can use the standard cache backends
+as reference implementations. You'll find the code in the
+``django/core/cache/backends/`` directory of the Django source.
+
+Note: Without a really compelling reason, such as a host that doesn't support
+them, you should stick to the cache backends included with Django. They've
+been well-tested and are easy to use.
+
+Cache arguments
+---------------
+
+In addition to the defining the engine and name of the each cache
+backend, each cache backend can be given additional arguments to
+control caching behavior. These arguments are provided as additional
+keys in the :setting:`CACHES` setting. Valid arguments are as follows:
+
+    * :setting:`TIMEOUT <CACHES-TIMEOUT>`: The default timeout, in
+      seconds, to use for the cache. This argument defaults to 300
+      seconds (5 minutes).
+
+    * :setting:`OPTIONS <CACHES-OPTIONS>`: Any options that should be
+      passed to cache backend. The list options understood by each
+      backend vary with each backend.
+
+      Cache backends that implement their own culling strategy (i.e.,
+      the ``locmem``, ``filesystem`` and ``database`` backends) will
+      honor the following options:
+
+        * ``MAX_ENTRIES``: the maximum number of entries allowed in
+          the cache before old values are deleted. This argument
+          defaults to ``300``.
+
+        * ``CULL_FREQUENCY``: The fraction of entries that are culled
+          when ``MAX_ENTRIES`` is reached. The actual ratio is
+          ``1/CULL_FREQUENCY``, so set ``CULL_FREQUENCY``: to ``2`` to
+          cull half of the entries when ``MAX_ENTRIES`` is reached.
+
+          A value of ``0`` for ``CULL_FREQUENCY`` means that the
+          entire cache will be dumped when ``MAX_ENTRIES`` is reached.
+          This makes culling *much* faster at the expense of more
+          cache misses.
+
+      Cache backends backed by a third-party library will pass their
+      options directly to the underlying cache library. As a result,
+      the list of valid options depends on the library in use.
+
+    * :setting:`KEY_PREFIX <CACHES-KEY_PREFIX>`: A string that will be
+      automatically included (prepended by default) to all cache keys
+      used by the Django server.
+
+      See the :ref:`cache documentation <cache_key_prefixing>` for
+      more information.
+
+    * :setting:`VERSION <CACHES-VERSION>`: The default version number
+      for cache keys generated by the Django server.
+
+      See the :ref:`cache documentation <cache_versioning>` for more
+      information.
+
+    * :setting:`KEY_FUNCTION <CACHES-KEY_FUNCTION>`
+      A string containing a dotted path to a function that defines how
+      to compose a prefix, version and key into a final cache key.
+
+      See the :ref:`cache documentation <cache_key_transformation>`
+      for more information.
+
+In this example, a filesystem backend is being configured with a timeout
+of 60 seconds, and a maximum capacity of 1000 items::
+
+    CACHES = {
+        'default': {
+            'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
+            'LOCATION': '/var/tmp/django_cache',
+            'TIMEOUT': 60,
+            'OPTIONS': {
+                'MAX_ENTRIES': 1000
+            }
+        }
+    }
+
+Invalid arguments are silently ignored, as are invalid values of known
+arguments.
+
+The per-site cache
+==================
+
+Once the cache is set up, the simplest way to use caching is to cache your
+entire site. You'll need to add
+``'django.middleware.cache.UpdateCacheMiddleware'`` and
+``'django.middleware.cache.FetchFromCacheMiddleware'`` to your
+``MIDDLEWARE_CLASSES`` setting, as in this example::
+
+    MIDDLEWARE_CLASSES = (
+        'django.middleware.cache.UpdateCacheMiddleware',
+        'django.middleware.common.CommonMiddleware',
+        'django.middleware.cache.FetchFromCacheMiddleware',
+    )
+
+.. note::
+
+    No, that's not a typo: the "update" middleware must be first in the list,
+    and the "fetch" middleware must be last. The details are a bit obscure, but
+    see `Order of MIDDLEWARE_CLASSES`_ below if you'd like the full story.
+
+Then, add the following required settings to your Django settings file:
+
+* :setting:`CACHE_MIDDLEWARE_ALIAS` -- The cache alias to use for storage.
+* :setting:`CACHE_MIDDLEWARE_SECONDS` -- The number of seconds each page should
+  be cached.
+* :setting:`CACHE_MIDDLEWARE_KEY_PREFIX` -- If the cache is shared across
+  multiple sites using the same Django installation, set this to the name of
+  the site, or some other string that is unique to this Django instance, to
+  prevent key collisions. Use an empty string if you don't care.
+
+The cache middleware caches every page that doesn't have GET or POST
+parameters. Optionally, if the :setting:`CACHE_MIDDLEWARE_ANONYMOUS_ONLY`
+setting is ``True``, only anonymous requests (i.e., not those made by a
+logged-in user) will be cached. This is a simple and effective way of disabling
+caching for any user-specific pages (including Django's admin interface). Note
+that if you use :setting:`CACHE_MIDDLEWARE_ANONYMOUS_ONLY`, you should make
+sure you've activated ``AuthenticationMiddleware``. The cache middleware
+expects that a HEAD request is answered with the same response headers as
+the corresponding GET request; in which case it can return a cached GET
+response for HEAD request.
+
+Additionally, the cache middleware automatically sets a few headers in each
+:class:`~django.http.HttpResponse`:
+
+    * Sets the ``Last-Modified`` header to the current date/time when a fresh
+      (uncached) version of the page is requested.
+
+    * Sets the ``Expires`` header to the current date/time plus the defined
+      :setting:`CACHE_MIDDLEWARE_SECONDS`.
+
+    * Sets the ``Cache-Control`` header to give a max age for the page --
+      again, from the :setting:`CACHE_MIDDLEWARE_SECONDS` setting.
+
+See :doc:`/topics/http/middleware` for more on middleware.
+
+If a view sets its own cache expiry time (i.e. it has a ``max-age`` section in
+its ``Cache-Control`` header) then the page will be cached until the expiry
+time, rather than :setting:`CACHE_MIDDLEWARE_SECONDS`. Using the decorators in
+``django.views.decorators.cache`` you can easily set a view's expiry time
+(using the ``cache_control`` decorator) or disable caching for a view (using
+the ``never_cache`` decorator). See the `using other headers`__ section for
+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>`.
+This allows you to easily cache multilingual sites without having to create
+the cache key yourself.
+
+See :doc:`/topics/i18n/deployment` for more on how Django discovers the active
+language.
+
+__ `Controlling cache: Using other headers`_
+
+The per-view cache
+==================
+
+.. function ``django.views.decorators.cache.cache_page``
+
+A more granular way to use the caching framework is by caching the output of
+individual views. ``django.views.decorators.cache`` defines a ``cache_page``
+decorator that will automatically cache the view's response for you. It's easy
+to use::
+
+    from django.views.decorators.cache import cache_page
+
+    @cache_page(60 * 15)
+    def my_view(request):
+        ...
+
+``cache_page`` takes a single argument: the cache timeout, in seconds. In the
+above example, the result of the ``my_view()`` view will be cached for 15
+minutes. (Note that we've written it as ``60 * 15`` for the purpose of
+readability. ``60 * 15`` will be evaluated to ``900`` -- that is, 15 minutes
+multiplied by 60 seconds per minute.)
+
+The per-view cache, like the per-site cache, is keyed off of the URL. If
+multiple URLs point at the same view, each URL will be cached separately.
+Continuing the ``my_view`` example, if your URLconf looks like this::