diff options
Diffstat (limited to 'parts/django/docs/topics')
40 files changed, 18023 insertions, 0 deletions
diff --git a/parts/django/docs/topics/auth.txt b/parts/django/docs/topics/auth.txt new file mode 100644 index 0000000..a58e523 --- /dev/null +++ b/parts/django/docs/topics/auth.txt @@ -0,0 +1,1612 @@ +============================= +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. + * Messages: A simple way to queue messages for given users. + +.. deprecated:: 1.2 + The Messages component of the auth system will be removed in Django 1.4. + +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. E-mail 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() + + .. versionadded:: 1.0 + + 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() + + .. versionadded:: 1.0 + + 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.get_and_delete_messages() + + Returns a list of :class:`~django.contrib.auth.models.Message` objects + in the user's queue and deletes the messages from the queue. + + .. method:: models.User.email_user(subject, message, from_email=None) + + Sends an e-mail 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 convered 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. + +.. versionadded:: 1.0 + Support for the ``crypt`` module is new in Django 1.0. + +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 +------------------- + +.. versionadded:: 1.0 + The ``manage.py createsuperuser`` command is new. + +: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` 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 +----------------------------------- + +.. 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 +--------------------- + +.. 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. + + .. versionchanged:: 1.0 + Calling ``logout()`` now cleans session data. + + 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()`. + +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]) + + 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): + ... + + 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). + + Note that 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" %} + + {% 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/ + +Other built-in 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:: views.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:: views.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:: views.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:: views.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:: views.password_reset(request[, is_admin_site, template_name, email_template_name, password_reset_form, token_generator, post_reset_redirect]) + + 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 e-mail address. + + **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 e-mail 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. + + **Template context:** + + * ``form``: The form for resetting the user's password. + +.. function:: views.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:: views.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. + +.. 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`. + +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 e-mailing 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 + +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:: decorators.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:: decorators.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>`. + +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 appication:: + + 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 +------------- + +.. class:: models.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:: models.Permission.name + + Required. 50 characters or fewer. Example: ``'Can vote'``. + +.. attribute:: models.Permission.content_type + + Required. A reference to the ``django_content_type`` database table, which + contains a record for each installed Django model. + +.. attribute:: models.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>`. + +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.core.context_processors.PermWrapper`, which is a +template-friendly proxy of permissions. + +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 e-mail +messages. + +Messages +======== + +.. deprecated:: 1.2 + This functionality will be removed in Django 1.4. You should use the + :doc:`messages framework </ref/contrib/messages>` for all new projects and + begin to update your existing code immediately. + +The message system is a lightweight way to queue messages for given users. + +A message is associated with a :class:`~django.contrib.auth.models.User`. +There's no concept of expiration or timestamps. + +Messages are used by the Django admin after successful actions. For example, +``"The poll Foo was created successfully."`` is a message. + +The API is simple: + +.. method:: models.User.message_set.create(message) + + To create a new message, use + ``user_obj.message_set.create(message='message_text')``. + + To retrieve/delete messages, use + :meth:`user_obj.get_and_delete_messages() <django.contrib.auth.models.User.get_and_delete_messages>`, + which returns a list of ``Message`` objects in the user's queue (if any) + and deletes the messages from the queue. + +In this example view, the system saves a message for the user after creating +a playlist:: + + def create_playlist(request, songs): + # Create the playlist with the given songs. + # ... + request.user.message_set.create(message="Your playlist was added successfully.") + return render_to_response("playlists/create.html", + context_instance=RequestContext(request)) + +When you use :class:`~django.template.context.RequestContext`, the currently +logged-in user and his/her messages are made available in the +:doc:`template context </ref/templates/api>` as the template variable +``{{ messages }}``. Here's an example of template code that displays messages: + +.. code-block:: html+django + + {% if messages %} + <ul> + {% for message in messages %} + <li>{{ message }}</li> + {% endfor %} + </ul> + {% endif %} + +.. versionchanged:: 1.2 + The ``messages`` template variable uses a backwards compatible method in the + :doc:`messages framework </ref/contrib/messages>` to retrieve messages from + both the user ``Message`` model and from the new framework. Unlike in + previous revisions, the messages will not be erased unless they are actually + displayed. + +Finally, note that this messages framework only works with users in the user +database. To send messages to anonymous users, use the +:doc:`messages framework </ref/contrib/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' + """ + 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. + +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``. diff --git a/parts/django/docs/topics/cache.txt b/parts/django/docs/topics/cache.txt new file mode 100644 index 0000000..c18b811 --- /dev/null +++ b/parts/django/docs/topics/cache.txt @@ -0,0 +1,917 @@ +======================== +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 ``CACHE_BACKEND`` setting in your settings +file. Here's an explanation of all available values for ``CACHE_BACKEND``. + +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 +``python-memcached``, which provides Python bindings to Memcached. +This is available at ftp://ftp.tummy.com/pub/python-memcached/ + +.. 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. + +To use Memcached with Django, set ``CACHE_BACKEND`` to +``memcached://ip:port/``, 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:: + + CACHE_BACKEND = 'memcached://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 ``CACHE_BACKEND``, separated by semicolons. + +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:: + + CACHE_BACKEND = 'memcached://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):: + + CACHE_BACKEND = 'memcached://172.19.26.240:11211;172.19.26.242:11212;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 ``CACHE_BACKEND`` setting to +``"db://tablename"``, where ``tablename`` is the name of the database table. +In this example, the cache table's name is ``my_cache_table``:: + + CACHE_BACKEND = 'db://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 the ``"file://"`` cache type for +``CACHE_BACKEND``. For example, to store cached data in ``/var/tmp/django_cache``, +use this setting:: + + CACHE_BACKEND = 'file:///var/tmp/django_cache' + +Note that there are three forward slashes toward the beginning of that example. +The first two are for ``file://``, and the third is the first character of the +directory path, ``/var/tmp/django_cache``. If you're on Windows, put the +drive letter after the ``file://``, like this:: + + file://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 ``CACHE_BACKEND`` to +``"locmem://"``. For example:: + + CACHE_BACKEND = 'locmem://' + +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 ``CACHE_BACKEND`` like so:: + + CACHE_BACKEND = 'dummy://' + +Using a custom cache backend +---------------------------- + +.. versionadded:: 1.0 + +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 a Python import path as the scheme portion (the +part before the initial colon) of the ``CACHE_BACKEND`` URI, like so:: + + CACHE_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_BACKEND arguments +----------------------- + +Each cache backend may take arguments. They're given in query-string style on +the ``CACHE_BACKEND`` setting. Valid arguments are as follows: + + * ``timeout``: The default timeout, in seconds, to use for the cache. + This argument defaults to 300 seconds (5 minutes). + + * ``max_entries``: For the ``locmem``, ``filesystem`` and ``database`` + backends, 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=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. + +In this example, ``timeout`` is set to ``60``:: + + CACHE_BACKEND = "memcached://127.0.0.1:11211/?timeout=60" + +In this example, ``timeout`` is ``30`` and ``max_entries`` is ``400``:: + + CACHE_BACKEND = "locmem://?timeout=30&max_entries=400" + +Invalid arguments are silently ignored, as are invalid values of known +arguments. + +The per-site cache +================== + +.. versionchanged:: 1.0 + (previous versions of Django only provided a single ``CacheMiddleware`` instead + of the two pieces described below). + +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: + +* ``CACHE_MIDDLEWARE_SECONDS`` -- The number of seconds each page should be + cached. +* ``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 ``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 (include Django's admin interface). Note that if you use +``CACHE_MIDDLEWARE_ANONYMOUS_ONLY``, you should make sure you've activated +``AuthenticationMiddleware``. + +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 + ``CACHE_MIDDLEWARE_SECONDS``. + + * Sets the ``Cache-Control`` header to give a max age for the page -- + again, from the ``CACHE_MIDDLEWARE_SECONDS`` setting. + +See :doc:`/topics/http/middleware` for more on middleware. + +.. versionadded:: 1.0 + +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 ``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 +================== + +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:: + + urlpatterns = ('', + (r'^foo/(\d{1,2})/$', my_view), + ) + +then requests to ``/foo/1/`` and ``/foo/23/`` will be cached separately, as +you may expect. But once a particular URL (e.g., ``/foo/23/``) has been +requested, subsequent requests to that URL will use the cache. + +``cache_page`` can also take an optional keyword argument, ``key_prefix``, which +works in the same way as the ``CACHE_MIDDLEWARE_KEY_PREFIX`` setting for the +middleware. It can be used like this:: + + @cache_page(60 * 15, key_prefix="site1") + def my_view(request): + ... + +Specifying per-view cache in the URLconf +---------------------------------------- + +The examples in the previous section have hard-coded the fact that the view is +cached, because ``cache_page`` alters the ``my_view`` function in place. This +approach couples your view to the cache system, which is not ideal for several +reasons. For instance, you might want to reuse the view functions on another, +cache-less site, or you might want to distribute the views to people who might +want to use them without being cached. The solution to these problems is to +specify the per-view cache in the URLconf rather than next to the view functions +themselves. + +Doing so is easy: simply wrap the view function with ``cache_page`` when you +refer to it in the URLconf. Here's the old URLconf from earlier:: + + urlpatterns = ('', + (r'^foo/(\d{1,2})/$', my_view), + ) + +Here's the same thing, with ``my_view`` wrapped in ``cache_page``:: + + from django.views.decorators.cache import cache_page + + urlpatterns = ('', + (r'^foo/(\d{1,2})/$', cache_page(my_view, 60 * 15)), + ) + +If you take this approach, don't forget to import ``cache_page`` within your +URLconf. + +Template fragment caching +========================= + +.. versionadded:: 1.0 + +If you're after even more control, you can also cache template fragments using +the ``cache`` template tag. To give your template access to this tag, put +``{% load cache %}`` near the top of your template. + +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: + +.. code-block:: html+django + + {% load cache %} + {% cache 500 sidebar %} + .. sidebar .. + {% endcache %} + +Sometimes you might want to cache multiple copies of a fragment depending on +some dynamic data that appears inside the fragment. For example, you might want a +separate cached copy of the sidebar used in the previous example for every user +of your site. Do this by passing additional arguments to the ``{% cache %}`` +template tag to uniquely identify the cache fragment: + +.. code-block:: html+django + + {% load cache %} + {% cache 500 sidebar request.user.username %} + .. sidebar for logged in user .. + {% endcache %} + +It's perfectly fine to specify more than one argument to identify the fragment. +Simply pass as many arguments to ``{% cache %}`` as you need. + +If :setting:`USE_I18N` is set to ``True`` the per-site middleware cache will +:ref:`respect the active language<i18n-cache-key>`. For the ``cache`` template +tag you could use one of the +:ref:`translation-specific variables<template-translation-vars>` available in +templates to archieve the same result: + +.. code-block:: html+django + + {% load i18n %} + {% load cache %} + + {% get_current_language as LANGUAGE_CODE %} + + {% cache 600 welcome LANGUAGE_CODE %} + {% trans "Welcome to example.com" %} + {% endcache %} + +The cache timeout can be a template variable, as long as the template variable +resolves to an integer value. For example, if the template variable +``my_timeout`` is set to the value ``600``, then the following two examples are +equivalent: + +.. code-block:: html+django + + {% cache 600 sidebar %} ... {% endcache %} + {% cache my_timeout sidebar %} ... {% endcache %} + +This feature is useful in avoiding repetition in templates. You can set the +timeout in a variable, in one place, and just reuse that value. + +The low-level cache API +======================= + +.. highlight:: python + +Sometimes, caching an entire rendered page doesn't gain you very much and is, +in fact, inconvenient overkill. + +Perhaps, for instance, your site includes a view whose results depend on +several expensive queries, the results of which change at different intervals. +In this case, it would not be ideal to use the full-page caching that the +per-site or per-view cache strategies offer, because you wouldn't want to +cache the entire result (since some of the data changes often), but you'd still +want to cache the results that rarely change. + +For cases like this, Django exposes a simple, low-level cache API. You can use +this API to store objects in the cache with any level of granularity you like. +You can cache any Python object that can be pickled safely: strings, +dictionaries, lists of model objects, and so forth. (Most common Python objects +can be pickled; refer to the Python documentation for more information about +pickling.) + +The cache module, ``django.core.cache``, has a ``cache`` object that's +automatically created from the ``CACHE_BACKEND`` setting:: + + >>> from django.core.cache import cache + +The basic interface is ``set(key, value, timeout)`` and ``get(key)``:: + + >>> cache.set('my_key', 'hello, world!', 30) + >>> cache.get('my_key') + 'hello, world!' + +The ``timeout`` argument is optional and defaults to the ``timeout`` +argument in the ``CACHE_BACKEND`` setting (explained above). It's the number of +seconds the value should be stored in the cache. + +If the object doesn't exist in the cache, ``cache.get()`` returns ``None``:: + + # Wait 30 seconds for 'my_key' to expire... + + >>> cache.get('my_key') + None + +We advise against storing the literal value ``None`` in the cache, because you +won't be able to distinguish between your stored ``None`` value and a cache +miss signified by a return value of ``None``. + +``cache.get()`` can take a ``default`` argument. This specifies which value to +return if the object doesn't exist in the cache:: + + >>> cache.get('my_key', 'has expired') + 'has expired' + +.. versionadded:: 1.0 + +To add a key only if it doesn't already exist, use the ``add()`` method. +It takes the same parameters as ``set()``, but it will not attempt to +update the cache if the key specified is already present:: + + >>> cache.set('add_key', 'Initial value') + >>> cache.add('add_key', 'New value') + >>> cache.get('add_key') + 'Initial value' + +If you need to know whether ``add()`` stored a value in the cache, you can +check the return value. It will return ``True`` if the value was stored, +``False`` otherwise. + +There's also a ``get_many()`` interface that only hits the cache once. +``get_many()`` returns a dictionary with all the keys you asked for that +actually exist in the cache (and haven't expired):: + + >>> cache.set('a', 1) + >>> cache.set('b', 2) + >>> cache.set('c', 3) + >>> 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:: + + >>> cache.set_many({'a': 1, 'b': 2, 'c': 3}) + >>> cache.get_many(['a', 'b', 'c']) + {'a': 1, 'b': 2, 'c': 3} + +Like ``cache.set()``, ``set_many()`` takes an optional ``timeout`` parameter. + +You can delete keys explicitly with ``delete()``. This is an easy way of +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. :: + + >>> cache.clear() + +.. versionadded:: 1.1 + +You can also increment or decrement a key that already exists using the +``incr()`` or ``decr()`` methods, respectively. By default, the existing cache +value will incremented or decremented by 1. Other increment/decrement values +can be specified by providing an argument to the increment/decrement call. A +ValueError will be raised if you attempt to increment or decrement a +nonexistent cache key.:: + + >>> cache.set('num', 1) + >>> cache.incr('num') + 2 + >>> cache.incr('num', 10) + 12 + >>> cache.decr('num') + 11 + >>> cache.decr('num', 5) + 6 + +.. note:: + + ``incr()``/``decr()`` methods are not guaranteed to be atomic. On those + backends that support atomic increment/decrement (most notably, the + memcached backend), increment and decrement operations will be atomic. + However, if the backend doesn't natively provide an increment/decrement + operation, it will be implemented using a two-step retrieve/update. + +Cache key warnings +------------------ + +.. versionadded:: 1.3 + +Memcached, the most commonly-used production cache backend, does not allow +cache keys longer than 250 characters or containing whitespace or control +characters, and using such keys will cause an exception. To encourage +cache-portable code and minimize unpleasant surprises, the other built-in cache +backends issue a warning (``django.core.cache.backends.base.CacheKeyWarning``) +if a key is used that would cause an error on memcached. + +If you are using a production backend that can accept a wider range of keys (a +custom backend, or one of the non-memcached built-in backends), and want to use +this wider range without warnings, you can silence ``CacheKeyWarning`` with +this code in the ``management`` module of one of your +:setting:`INSTALLED_APPS`:: + + import warnings + + from django.core.cache import CacheKeyWarning + + warnings.simplefilter("ignore", CacheKeyWarning) + +If you want to instead provide custom key validation logic for one of the +built-in backends, you can subclass it, override just the ``validate_key`` +method, and follow the instructions for `using a custom cache backend`_. For +instance, to do this for the ``locmem`` backend, put this code in a module:: + + from django.core.cache.backends.locmem import CacheClass as LocMemCacheClass + + class CacheClass(LocMemCacheClass): + def validate_key(self, key): + """Custom validation, raising exceptions or warnings as needed.""" + # ... + +...and use the dotted Python path to this module as the scheme portion of your +:setting:`CACHE_BACKEND`. + +Upstream caches +=============== + +So far, this document has focused on caching your *own* data. But another type +of caching is relevant to Web development, too: caching performed by "upstream" +caches. These are systems that cache pages for users even before the request +reaches your Web site. + +Here are a few examples of upstream caches: + + * Your ISP may cache certain pages, so if you requested a page from + http://example.com/, your ISP would send you the page without having to + access example.com directly. The maintainers of example.com have no + knowledge of this caching; the ISP sits between example.com and your Web + browser, handling all of the caching transparently. + + * Your Django Web site may sit behind a *proxy cache*, such as Squid Web + Proxy Cache (http://www.squid-cache.org/), that caches pages for + performance. In this case, each request first would be handled by the + proxy, and it would be passed to your application only if needed. + + * Your Web browser caches pages, too. If a Web page sends out the + appropriate headers, your browser will use the local cached copy for + subsequent requests to that page, without even contacting the Web page + again to see whether it has changed. + +Upstream caching is a nice efficiency boost, but there's a danger to it: +Many Web pages' contents differ based on authentication and a host of other +variables, and cache systems that blindly save pages based purely on URLs could +expose incorrect or sensitive data to subsequent visitors to those pages. + +For example, say you operate a Web e-mail system, and the contents of the +"inbox" page obviously depend on which user is logged in. If an ISP blindly +cached your site, then the first user who logged in through that ISP would have +his user-specific inbox page cached for subsequent visitors to the site. That's +not cool. + +Fortunately, HTTP provides a solution to this problem. A number of HTTP headers +exist to instruct upstream caches to differ their cache contents depending on +designated variables, and to tell caching mechanisms not to cache particular +pages. We'll look at some of these headers in the sections that follow. + +Using Vary headers +================== + +The ``Vary`` header defines which request headers a cache +mechanism should take into account when building its cache key. For example, if +the contents of a Web page depend on a user's language preference, the page is +said to "vary on language." + +By default, Django's cache system creates its cache keys using the requested +path (e.g., ``"/stories/2005/jun/23/bank_robbed/"``). This means every request +to that URL will use the same cached version, regardless of user-agent +differences such as cookies or language preferences. However, if this page +produces different content based on some difference in request headers -- such +as a cookie, or a language, or a user-agent -- you'll need to use the ``Vary`` +header to tell caching mechanisms that the page output depends on those things. + +To do this in Django, use the convenient ``vary_on_headers`` view decorator, +like so:: + + from django.views.decorators.vary import vary_on_headers + + @vary_on_headers('User-Agent') + def my_view(request): + # ... + +In this case, a caching mechanism (such as Django's own cache middleware) will +cache a separate version of the page for each unique user-agent. + +The advantage to using the ``vary_on_headers`` decorator rather than manually +setting the ``Vary`` header (using something like +``response['Vary'] = 'user-agent'``) is that the decorator *adds* to the +``Vary`` header (which may already exist), rather than setting it from scratch +and potentially overriding anything that was already in there. + +You can pass multiple headers to ``vary_on_headers()``:: + + @vary_on_headers('User-Agent', 'Cookie') + def my_view(request): + # ... + +This tells upstream caches to vary on *both*, which means each combination of +user-agent and cookie will get its own cache value. For example, a request with +the user-agent ``Mozilla`` and the cookie value ``foo=bar`` will be considered +different from a request with the user-agent ``Mozilla`` and the cookie value +``foo=ham``. + +Because varying on cookie is so common, there's a ``vary_on_cookie`` +decorator. These two views are equivalent:: + + @vary_on_cookie + def my_view(request): + # ... + + @vary_on_headers('Cookie') + def my_view(request): + # ... + +The headers you pass to ``vary_on_headers`` are not case sensitive; +``"User-Agent"`` is the same thing as ``"user-agent"``. + +You can also use a helper function, ``django.utils.cache.patch_vary_headers``, +directly. This function sets, or adds to, the ``Vary header``. For example:: + + from django.utils.cache import patch_vary_headers + + def my_view(request): + # ... + response = render_to_response('template_name', context) + patch_vary_headers(response, ['Cookie']) + return response + +``patch_vary_headers`` takes an :class:`~django.http.HttpResponse` instance as +its first argument and a list/tuple of case-insensitive header names as its +second argument. + +For more on Vary headers, see the `official Vary spec`_. + +.. _`official Vary spec`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.44 + +Controlling cache: Using other headers +====================================== + +Other problems with caching are the privacy of data and the question of where +data should be stored in a cascade of caches. + +A user usually faces two kinds of caches: his or her own browser cache (a +private cache) and his or her provider's cache (a public cache). A public cache +is used by multiple users and controlled by someone else. This poses problems +with sensitive data--you don't want, say, your bank account number stored in a +public cache. So Web applications need a way to tell caches which data is +private and which is public. + +The solution is to indicate a page's cache should be "private." To do this in +Django, use the ``cache_control`` view decorator. Example:: + + from django.views.decorators.cache import cache_control + + @cache_control(private=True) + def my_view(request): + # ... + +This decorator takes care of sending out the appropriate HTTP header behind the +scenes. + +There are a few other ways to control cache parameters. For example, HTTP +allows applications to do the following: + + * Define the maximum time a page should be cached. + + * Specify whether a cache should always check for newer versions, only + delivering the cached content when there are no changes. (Some caches + might deliver cached content even if the server page changed, simply + because the cache copy isn't yet expired.) + +In Django, use the ``cache_control`` view decorator to specify these cache +parameters. In this example, ``cache_control`` tells caches to revalidate the +cache on every access and to store cached versions for, at most, 3,600 seconds:: + + from django.views.decorators.cache import cache_control + + @cache_control(must_revalidate=True, max_age=3600) + def my_view(request): + # ... + +Any valid ``Cache-Control`` HTTP directive is valid in ``cache_control()``. +Here's a full list: + + * ``public=True`` + * ``private=True`` + * ``no_cache=True`` + * ``no_transform=True`` + * ``must_revalidate=True`` + * ``proxy_revalidate=True`` + * ``max_age=num_seconds`` + * ``s_maxage=num_seconds`` + +For explanation of Cache-Control HTTP directives, see the `Cache-Control spec`_. + +(Note that the caching middleware already sets the cache header's max-age with +the value of the :setting:`CACHE_MIDDLEWARE_SECONDS` setting. If you use a custom +``max_age`` in a ``cache_control`` decorator, the decorator will take +precedence, and the header values will be merged correctly.) + +If you want to use headers to disable caching altogether, +``django.views.decorators.cache.never_cache`` is a view decorator that adds +headers to ensure the response won't be cached by browsers or other caches. +Example:: + + from django.views.decorators.cache import never_cache + + @never_cache + def myview(request): + # ... + +.. _`Cache-Control spec`: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9 + +Other optimizations +=================== + +Django comes with a few other pieces of middleware that can help optimize your +site's performance: + + * ``django.middleware.http.ConditionalGetMiddleware`` adds support for + modern browsers to conditionally GET responses based on the ``ETag`` + and ``Last-Modified`` headers. + + * ``django.middleware.gzip.GZipMiddleware`` compresses responses for all + moderns browsers, saving bandwidth and transfer time. + +Order of MIDDLEWARE_CLASSES +=========================== + +If you use caching middleware, it's important to put each half in the right +place within the ``MIDDLEWARE_CLASSES`` setting. That's because the cache +middleware needs to know which headers by which to vary the cache storage. +Middleware always adds something to the ``Vary`` response header when it can. + +``UpdateCacheMiddleware`` runs during the response phase, where middleware is +run in reverse order, so an item at the top of the list runs *last* during the +response phase. Thus, you need to make sure that ``UpdateCacheMiddleware`` +appears *before* any other middleware that might add something to the ``Vary`` +header. The following middleware modules do so: + + * ``SessionMiddleware`` adds ``Cookie`` + * ``GZipMiddleware`` adds ``Accept-Encoding`` + * ``LocaleMiddleware`` adds ``Accept-Language`` + +``FetchFromCacheMiddleware``, on the other hand, runs during the request phase, +where middleware is applied first-to-last, so an item at the top of the list +runs *first* during the request phase. The ``FetchFromCacheMiddleware`` also +needs to run after other middleware updates the ``Vary`` header, so +``FetchFromCacheMiddleware`` must be *after* any item that does so. + diff --git a/parts/django/docs/topics/conditional-view-processing.txt b/parts/django/docs/topics/conditional-view-processing.txt new file mode 100644 index 0000000..c631a13 --- /dev/null +++ b/parts/django/docs/topics/conditional-view-processing.txt @@ -0,0 +1,199 @@ +=========================== +Conditional View Processing +=========================== + +.. versionadded:: 1.1 + +HTTP clients can send a number of headers to tell the server about copies of a +resource that they have already seen. This is commonly used when retrieving a +Web page (using an HTTP ``GET`` request) to avoid sending all the data for +something the client has already retrieved. However, the same headers can be +used for all HTTP methods (``POST``, ``PUT``, ``DELETE``, etc). + +For each page (response) that Django sends back from a view, it might provide +two HTTP headers: the ``ETag`` header and the ``Last-Modified`` header. These +headers are optional on HTTP responses. They can be set by your view function, +or you can rely on the :class:`~django.middleware.common.CommonMiddleware` +middleware to set the ``ETag`` header. + +When the client next requests the same resource, it might send along a header +such as `If-modified-since`_, containing the date of the last modification +time it was sent, or `If-none-match`_, containing the ``ETag`` it was sent. +If the current version of the page matches the ``ETag`` sent by the client, or +if the resource has not been modified, a 304 status code can be sent back, +instead of a full response, telling the client that nothing has changed. + +.. _If-none-match: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26 +.. _If-modified-since: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25 + +When you need more fine-grained control you may use per-view conditional +processing functions. + +.. conditional-decorators: + +The ``condition`` decorator +=========================== + +Sometimes (in fact, quite often) you can create functions to rapidly compute the ETag_ +value or the last-modified time for a resource, **without** needing to do all +the computations needed to construct the full view. Django can then use these +functions to provide an "early bailout" option for the view processing. +Telling the client that the content has not been modified since the last +request, perhaps. + +.. _ETag: http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.11 + +These two functions are passed as parameters the +``django.views.decorators.http.condition`` decorator. This decorator uses +the two functions (you only need to supply one, if you can't compute both +quantities easily and quickly) to work out if the headers in the HTTP request +match those on the resource. If they don't match, a new copy of the resource +must be computed and your normal view is called. + +The ``condition`` decorator's signature looks like this:: + + condition(etag_func=None, last_modified_func=None) + +The two functions, to compute the ETag and the last modified time, will be +passed the incoming ``request`` object and the same parameters, in the same +order, as the view function they are helping to wrap. The function passed +``last_modified_func`` should return a standard datetime value specifying the +last time the resource was modified, or ``None`` if the resource doesn't +exist. The function passed to the ``etag`` decorator should return a string +representing the `Etag`_ for the resource, or ``None`` if it doesn't exist. + +Using this feature usefully is probably best explained with an example. +Suppose you have this pair of models, representing a simple blog system:: + + import datetime + from django.db import models + + class Blog(models.Model): + ... + + class Entry(models.Model): + blog = models.ForeignKey(Blog) + published = models.DateTimeField(default=datetime.datetime.now) + ... + +If the front page, displaying the latest blog entries, only changes when you +add a new blog entry, you can compute the last modified time very quickly. You +need the latest ``published`` date for every entry associated with that blog. +One way to do this would be:: + + def latest_entry(request, blog_id): + return Entry.objects.filter(blog=blog_id).latest("published").published + +You can then use this function to provide early detection of an unchanged page +for your front page view:: + + from django.views.decorators.http import condition + + @condition(last_modified_func=latest_entry) + def front_page(request, blog_id): + ... + +Shortcuts for only computing one value +====================================== + +As a general rule, if you can provide functions to compute *both* the ETag and +the last modified time, you should do so. You don't know which headers any +given HTTP client will send you, so be prepared to handle both. However, +sometimes only one value is easy to compute and Django provides decorators +that handle only ETag or only last-modified computations. + +The ``django.views.decorators.http.etag`` and +``django.views.decorators.http.last_modified`` decorators are passed the same +type of functions as the ``condition`` decorator. Their signatures are:: + + etag(etag_func) + last_modified(last_modified_func) + +We could write the earlier example, which only uses a last-modified function, +using one of these decorators:: + + @last_modified(latest_entry) + def front_page(request, blog_id): + ... + +...or:: + + def front_page(request, blog_id): + ... + front_page = last_modified(latest_entry)(front_page) + +Use ``condition`` when testing both conditions +------------------------------------------------ + +It might look nicer to some people to try and chain the ``etag`` and +``last_modified`` decorators if you want to test both preconditions. However, +this would lead to incorrect behavior. + +:: + + # Bad code. Don't do this! + @etag(etag_func) + @last_modified(last_modified_func) + def my_view(request): + # ... + + # End of bad code. + +The first decorator doesn't know anything about the second and might +answer that the response is not modified even if the second decorators would +determine otherwise. The ``condition`` decorator uses both callback functions +simultaneously to work out the right action to take. + +Using the decorators with other HTTP methods +============================================ + +The ``condition`` decorator is useful for more than only ``GET`` and +``HEAD`` requests (``HEAD`` requests are the same as ``GET`` in this +situation). It can be used also to be used to provide checking for ``POST``, +``PUT`` and ``DELETE`` requests. In these situations, the idea isn't to return +a "not modified" response, but to tell the client that the resource they are +trying to change has been altered in the meantime. + +For example, consider the following exchange between the client and server: + + 1. Client requests ``/foo/``. + 2. Server responds with some content with an ETag of ``"abcd1234"``. + 3. Client sends an HTTP ``PUT`` request to ``/foo/`` to update the + resource. It also sends an ``If-Match: "abcd1234"`` header to specify + the version it is trying to update. + 4. Server checks to see if the resource has changed, by computing the ETag + the same way it does for a ``GET`` request (using the same function). + If the resource *has* changed, it will return a 412 status code code, + meaning "precondition failed". + 5. Client sends a ``GET`` request to ``/foo/``, after receiving a 412 + response, to retrieve an updated version of the content before updating + it. + +The important thing this example shows is that the same functions can be used +to compute the ETag and last modification values in all situations. In fact, +you **should** use the same functions, so that the same values are returned +every time. + +Comparison with middleware conditional processing +================================================= + +You may notice that Django already provides simple and straightforward +conditional ``GET`` handling via the +:class:`django.middleware.http.ConditionalGetMiddleware` and +:class:`~django.middleware.common.CommonMiddleware`. Whilst certainly being +easy to use and suitable for many situations, those pieces of middleware +functionality have limitations for advanced usage: + + * They are applied globally to all views in your project + * They don't save you from generating the response itself, which may be + expensive + * They are only appropriate for HTTP ``GET`` requests. + +You should choose the most appropriate tool for your particular problem here. +If you have a way to compute ETags and modification times quickly and if some +view takes a while to generate the content, you should consider using the +``condition`` decorator described in this document. If everything already runs +fairly quickly, stick to using the middleware and the amount of network +traffic sent back to the clients will still be reduced if the view hasn't +changed. + diff --git a/parts/django/docs/topics/db/aggregation.txt b/parts/django/docs/topics/db/aggregation.txt new file mode 100644 index 0000000..eb21021 --- /dev/null +++ b/parts/django/docs/topics/db/aggregation.txt @@ -0,0 +1,378 @@ +=========== +Aggregation +=========== + +.. versionadded:: 1.1 + +.. currentmodule:: django.db.models + +The topic guide on :doc:`Django's database-abstraction API </topics/db/queries>` +described the way that you can use Django queries that create, +retrieve, update and delete individual objects. However, sometimes you will +need to retrieve values that are derived by summarizing or *aggregating* a +collection of objects. This topic guide describes the ways that aggregate values +can be generated and returned using Django queries. + +Throughout this guide, we'll refer to the following models. These models are +used to track the inventory for a series of online bookstores: + +.. _queryset-model-example: + +.. code-block:: python + + class Author(models.Model): + name = models.CharField(max_length=100) + age = models.IntegerField() + friends = models.ManyToManyField('self', blank=True) + + class Publisher(models.Model): + name = models.CharField(max_length=300) + num_awards = models.IntegerField() + + class Book(models.Model): + isbn = models.CharField(max_length=9) + name = models.CharField(max_length=300) + pages = models.IntegerField() + price = models.DecimalField(max_digits=10, decimal_places=2) + rating = models.FloatField() + authors = models.ManyToManyField(Author) + publisher = models.ForeignKey(Publisher) + pubdate = models.DateField() + + class Store(models.Model): + name = models.CharField(max_length=300) + books = models.ManyToManyField(Book) + + +Generating aggregates over a QuerySet +===================================== + +Django provides two ways to generate aggregates. The first way is to generate +summary values over an entire ``QuerySet``. For example, say you wanted to +calculate the average price of all books available for sale. Django's query +syntax provides a means for describing the set of all books:: + + >>> Book.objects.all() + +What we need is a way to calculate summary values over the objects that +belong to this ``QuerySet``. This is done by appending an ``aggregate()`` +clause onto the ``QuerySet``:: + + >>> from django.db.models import Avg + >>> Book.objects.all().aggregate(Avg('price')) + {'price__avg': 34.35} + +The ``all()`` is redundant in this example, so this could be simplified to:: + + >>> Book.objects.aggregate(Avg('price')) + {'price__avg': 34.35} + +The argument to the ``aggregate()`` clause describes the aggregate value that +we want to compute - in this case, the average of the ``price`` field on the +``Book`` model. A list of the aggregate functions that are available can be +found in the :ref:`QuerySet reference <aggregation-functions>`. + +``aggregate()`` is a terminal clause for a ``QuerySet`` that, when invoked, +returns a dictionary of name-value pairs. The name is an identifier for the +aggregate value; the value is the computed aggregate. The name is +automatically generated from the name of the field and the aggregate function. +If you want to manually specify a name for the aggregate value, you can do so +by providing that name when you specify the aggregate clause:: + + >>> Book.objects.aggregate(average_price=Avg('price')) + {'average_price': 34.35} + +If you want to generate more than one aggregate, you just add another +argument to the ``aggregate()`` clause. So, if we also wanted to know +the maximum and minimum price of all books, we would issue the query:: + + >>> from django.db.models import Avg, Max, Min, Count + >>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price')) + {'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')} + +Generating aggregates for each item in a QuerySet +================================================= + +The second way to generate summary values is to generate an independent +summary for each object in a ``QuerySet``. For example, if you are retrieving +a list of books, you may want to know how many authors contributed to +each book. Each Book has a many-to-many relationship with the Author; we +want to summarize this relationship for each book in the ``QuerySet``. + +Per-object summaries can be generated using the ``annotate()`` clause. +When an ``annotate()`` clause is specified, each object in the ``QuerySet`` +will be annotated with the specified values. + +The syntax for these annotations is identical to that used for the +``aggregate()`` clause. Each argument to ``annotate()`` describes an +aggregate that is to be calculated. For example, to annotate Books with +the number of authors:: + + # Build an annotated queryset + >>> q = Book.objects.annotate(Count('authors')) + # Interrogate the first object in the queryset + >>> q[0] + <Book: The Definitive Guide to Django> + >>> q[0].authors__count + 2 + # Interrogate the second object in the queryset + >>> q[1] + <Book: Practical Django Projects> + >>> q[1].authors__count + 1 + +As with ``aggregate()``, the name for the annotation is automatically derived +from the name of the aggregate function and the name of the field being +aggregated. You can override this default name by providing an alias when you +specify the annotation:: + + >>> q = Book.objects.annotate(num_authors=Count('authors')) + >>> q[0].num_authors + 2 + >>> q[1].num_authors + 1 + +Unlike ``aggregate()``, ``annotate()`` is *not* a terminal clause. The output +of the ``annotate()`` clause is a ``QuerySet``; this ``QuerySet`` can be +modified using any other ``QuerySet`` operation, including ``filter()``, +``order_by``, or even additional calls to ``annotate()``. + +Joins and aggregates +==================== + +So far, we have dealt with aggregates over fields that belong to the +model being queried. However, sometimes the value you want to aggregate +will belong to a model that is related to the model you are querying. + +When specifying the field to be aggregated in an aggregate function, Django +will allow you to use the same :ref:`double underscore notation +<field-lookups-intro>` that is used when referring to related fields in +filters. Django will then handle any table joins that are required to retrieve +and aggregate the related value. + +For example, to find the price range of books offered in each store, +you could use the annotation:: + + >>> Store.objects.annotate(min_price=Min('books__price'), max_price=Max('books__price')) + +This tells Django to retrieve the Store model, join (through the +many-to-many relationship) with the Book model, and aggregate on the +price field of the book model to produce a minimum and maximum value. + +The same rules apply to the ``aggregate()`` clause. If you wanted to +know the lowest and highest price of any book that is available for sale +in a store, you could use the aggregate:: + + >>> Store.objects.aggregate(min_price=Min('books__price'), max_price=Max('books__price')) + +Join chains can be as deep as you require. For example, to extract the +age of the youngest author of any book available for sale, you could +issue the query:: + + >>> Store.objects.aggregate(youngest_age=Min('books__authors__age')) + +Aggregations and other QuerySet clauses +======================================= + +``filter()`` and ``exclude()`` +------------------------------ + +Aggregates can also participate in filters. Any ``filter()`` (or +``exclude()``) applied to normal model fields will have the effect of +constraining the objects that are considered for aggregation. + +When used with an ``annotate()`` clause, a filter has the effect of +constraining the objects for which an annotation is calculated. For example, +you can generate an annotated list of all books that have a title starting +with "Django" using the query:: + + >>> Book.objects.filter(name__startswith="Django").annotate(num_authors=Count('authors')) + +When used with an ``aggregate()`` clause, a filter has the effect of +constraining the objects over which the aggregate is calculated. +For example, you can generate the average price of all books with a +title that starts with "Django" using the query:: + + >>> Book.objects.filter(name__startswith="Django").aggregate(Avg('price')) + +Filtering on annotations +~~~~~~~~~~~~~~~~~~~~~~~~ + +Annotated values can also be filtered. The alias for the annotation can be +used in ``filter()`` and ``exclude()`` clauses in the same way as any other +model field. + +For example, to generate a list of books that have more than one author, +you can issue the query:: + + >>> Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1) + +This query generates an annotated result set, and then generates a filter +based upon that annotation. + +Order of ``annotate()`` and ``filter()`` clauses +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When developing a complex query that involves both ``annotate()`` and +``filter()`` clauses, particular attention should be paid to the order +in which the clauses are applied to the ``QuerySet``. + +When an ``annotate()`` clause is applied to a query, the annotation is +computed over the state of the query up to the point where the annotation +is requested. The practical implication of this is that ``filter()`` and +``annotate()`` are not commutative operations -- that is, there is a +difference between the query:: + + >>> Publisher.objects.annotate(num_books=Count('book')).filter(book__rating__gt=3.0) + +and the query:: + + >>> Publisher.objects.filter(book__rating__gt=3.0).annotate(num_books=Count('book')) + +Both queries will return a list of Publishers that have at least one good +book (i.e., a book with a rating exceeding 3.0). However, the annotation in +the first query will provide the total number of all books published by the +publisher; the second query will only include good books in the annotated +count. In the first query, the annotation precedes the filter, so the +filter has no effect on the annotation. In the second query, the filter +preceeds the annotation, and as a result, the filter constrains the objects +considered when calculating the annotation. + +``order_by()`` +-------------- + +Annotations can be used as a basis for ordering. When you +define an ``order_by()`` clause, the aggregates you provide can reference +any alias defined as part of an ``annotate()`` clause in the query. + +For example, to order a ``QuerySet`` of books by the number of authors +that have contributed to the book, you could use the following query:: + + >>> Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors') + +``values()`` +------------ + +Ordinarily, annotations are generated on a per-object basis - an annotated +``QuerySet`` will return one result for each object in the original +``QuerySet``. However, when a ``values()`` clause is used to constrain the +columns that are returned in the result set, the method for evaluating +annotations is slightly different. Instead of returning an annotated result +for each result in the original ``QuerySet``, the original results are +grouped according to the unique combinations of the fields specified in the +``values()`` clause. An annotation is then provided for each unique group; +the annotation is computed over all members of the group. + +For example, consider an author query that attempts to find out the average +rating of books written by each author: + + >>> Author.objects.annotate(average_rating=Avg('book__rating')) + +This will return one result for each author in the database, annotated with +their average book rating. + +However, the result will be slightly different if you use a ``values()`` clause:: + + >>> Author.objects.values('name').annotate(average_rating=Avg('book__rating')) + +In this example, the authors will be grouped by name, so you will only get +an annotated result for each *unique* author name. This means if you have +two authors with the same name, their results will be merged into a single +result in the output of the query; the average will be computed as the +average over the books written by both authors. + +Order of ``annotate()`` and ``values()`` clauses +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As with the ``filter()`` clause, the order in which ``annotate()`` and +``values()`` clauses are applied to a query is significant. If the +``values()`` clause precedes the ``annotate()``, the annotation will be +computed using the grouping described by the ``values()`` clause. + +However, if the ``annotate()`` clause precedes the ``values()`` clause, +the annotations will be generated over the entire query set. In this case, +the ``values()`` clause only constrains the fields that are generated on +output. + +For example, if we reverse the order of the ``values()`` and ``annotate()`` +clause from our previous example:: + + >>> Author.objects.annotate(average_rating=Avg('book__rating')).values('name', 'average_rating') + +This will now yield one unique result for each author; however, only +the author's name and the ``average_rating`` annotation will be returned +in the output data. + +You should also note that ``average_rating`` has been explicitly included +in the list of values to be returned. This is required because of the +ordering of the ``values()`` and ``annotate()`` clause. + +If the ``values()`` clause precedes the ``annotate()`` clause, any annotations +will be automatically added to the result set. However, if the ``values()`` +clause is applied after the ``annotate()`` clause, you need to explicitly +include the aggregate column. + +Interaction with default ordering or ``order_by()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Fields that are mentioned in the ``order_by()`` part of a queryset (or which +are used in the default ordering on a model) are used when selecting the +output data, even if they are not otherwise specified in the ``values()`` +call. These extra fields are used to group "like" results together and they +can make otherwise identical result rows appear to be separate. This shows up, +particularly, when counting things. + +By way of example, suppose you have a model like this:: + + class Item(models.Model): + name = models.CharField(max_length=10) + data = models.IntegerField() + + class Meta: + ordering = ["name"] + +The important part here is the default ordering on the ``name`` field. If you +want to count how many times each distinct ``data`` value appears, you might +try this:: + + # Warning: not quite correct! + Item.objects.values("data").annotate(Count("id")) + +...which will group the ``Item`` objects by their common ``data`` values and +then count the number of ``id`` values in each group. Except that it won't +quite work. The default ordering by ``name`` will also play a part in the +grouping, so this query will group by distinct ``(data, name)`` pairs, which +isn't what you want. Instead, you should construct this queryset:: + + Item.objects.values("data").annotate(Count("id")).order_by() + +...clearing any ordering in the query. You could also order by, say, ``data`` +without any harmful effects, since that is already playing a role in the +query. + +This behavior is the same as that noted in the queryset documentation for +:meth:`~django.db.models.QuerySet.distinct` and the general rule is the same: +normally you won't want extra columns playing a part in the result, so clear +out the ordering, or at least make sure it's restricted only to those fields +you also select in a ``values()`` call. + +.. note:: + You might reasonably ask why Django doesn't remove the extraneous columns + for you. The main reason is consistency with ``distinct()`` and other + places: Django **never** removes ordering constraints that you have + specified (and we can't change those other methods' behavior, as that + would violate our :doc:`/misc/api-stability` policy). + +Aggregating annotations +----------------------- + +You can also generate an aggregate on the result of an annotation. When you +define an ``aggregate()`` clause, the aggregates you provide can reference +any alias defined as part of an ``annotate()`` clause in the query. + +For example, if you wanted to calculate the average number of authors per +book you first annotate the set of books with the author count, then +aggregate that author count, referencing the annotation field:: + + >>> Book.objects.annotate(num_authors=Count('authors')).aggregate(Avg('num_authors')) + {'num_authors__avg': 1.66} diff --git a/parts/django/docs/topics/db/index.txt b/parts/django/docs/topics/db/index.txt new file mode 100644 index 0000000..c49f158 --- /dev/null +++ b/parts/django/docs/topics/db/index.txt @@ -0,0 +1,18 @@ +Models and databases +==================== + +A model is the single, definitive source of data about your data. It contains +the essential fields and behaviors of the data you're storing. Generally, each +model maps to a single database table. + +.. toctree:: + :maxdepth: 1 + + models + queries + aggregation + managers + sql + transactions + multi-db + optimization diff --git a/parts/django/docs/topics/db/managers.txt b/parts/django/docs/topics/db/managers.txt new file mode 100644 index 0000000..5ebe0b1 --- /dev/null +++ b/parts/django/docs/topics/db/managers.txt @@ -0,0 +1,376 @@ +======== +Managers +======== + +.. currentmodule:: django.db.models + +.. class:: Manager() + +A ``Manager`` is the interface through which database query operations are +provided to Django models. At least one ``Manager`` exists for every model in +a Django application. + +The way ``Manager`` classes work is documented in :doc:`/topics/db/queries`; +this document specifically touches on model options that customize ``Manager`` +behavior. + +.. _manager-names: + +Manager names +============= + +By default, Django adds a ``Manager`` with the name ``objects`` to every Django +model class. However, if you want to use ``objects`` as a field name, or if you +want to use a name other than ``objects`` for the ``Manager``, you can rename +it on a per-model basis. To rename the ``Manager`` for a given class, define a +class attribute of type ``models.Manager()`` on that model. For example:: + + from django.db import models + + class Person(models.Model): + #... + people = models.Manager() + +Using this example model, ``Person.objects`` will generate an +``AttributeError`` exception, but ``Person.people.all()`` will provide a list +of all ``Person`` objects. + +.. _custom-managers: + +Custom Managers +=============== + +You can use a custom ``Manager`` in a particular model by extending the base +``Manager`` class and instantiating your custom ``Manager`` in your model. + +There are two reasons you might want to customize a ``Manager``: to add extra +``Manager`` methods, and/or to modify the initial ``QuerySet`` the ``Manager`` +returns. + +Adding extra Manager methods +---------------------------- + +Adding extra ``Manager`` methods is the preferred way to add "table-level" +functionality to your models. (For "row-level" functionality -- i.e., functions +that act on a single instance of a model object -- use :ref:`Model methods +<model-methods>`, not custom ``Manager`` methods.) + +A custom ``Manager`` method can return anything you want. It doesn't have to +return a ``QuerySet``. + +For example, this custom ``Manager`` offers a method ``with_counts()``, which +returns a list of all ``OpinionPoll`` objects, each with an extra +``num_responses`` attribute that is the result of an aggregate query:: + + class PollManager(models.Manager): + def with_counts(self): + from django.db import connection + cursor = connection.cursor() + cursor.execute(""" + SELECT p.id, p.question, p.poll_date, COUNT(*) + FROM polls_opinionpoll p, polls_response r + WHERE p.id = r.poll_id + GROUP BY 1, 2, 3 + ORDER BY 3 DESC""") + result_list = [] + for row in cursor.fetchall(): + p = self.model(id=row[0], question=row[1], poll_date=row[2]) + p.num_responses = row[3] + result_list.append(p) + return result_list + + class OpinionPoll(models.Model): + question = models.CharField(max_length=200) + poll_date = models.DateField() + objects = PollManager() + + class Response(models.Model): + poll = models.ForeignKey(Poll) + person_name = models.CharField(max_length=50) + response = models.TextField() + +With this example, you'd use ``OpinionPoll.objects.with_counts()`` to return +that list of ``OpinionPoll`` objects with ``num_responses`` attributes. + +Another thing to note about this example is that ``Manager`` methods can +access ``self.model`` to get the model class to which they're attached. + +Modifying initial Manager QuerySets +----------------------------------- + +A ``Manager``'s base ``QuerySet`` returns all objects in the system. For +example, using this model:: + + class Book(models.Model): + title = models.CharField(max_length=100) + author = models.CharField(max_length=50) + +...the statement ``Book.objects.all()`` will return all books in the database. + +You can override a ``Manager``\'s base ``QuerySet`` by overriding the +``Manager.get_query_set()`` method. ``get_query_set()`` should return a +``QuerySet`` with the properties you require. + +For example, the following model has *two* ``Manager``\s -- one that returns +all objects, and one that returns only the books by Roald Dahl:: + + # First, define the Manager subclass. + class DahlBookManager(models.Manager): + def get_query_set(self): + return super(DahlBookManager, self).get_query_set().filter(author='Roald Dahl') + + # Then hook it into the Book model explicitly. + class Book(models.Model): + title = models.CharField(max_length=100) + author = models.CharField(max_length=50) + + objects = models.Manager() # The default manager. + dahl_objects = DahlBookManager() # The Dahl-specific manager. + +With this sample model, ``Book.objects.all()`` will return all books in the +database, but ``Book.dahl_objects.all()`` will only return the ones written by +Roald Dahl. + +Of course, because ``get_query_set()`` returns a ``QuerySet`` object, you can +use ``filter()``, ``exclude()`` and all the other ``QuerySet`` methods on it. +So these statements are all legal:: + + Book.dahl_objects.all() + Book.dahl_objects.filter(title='Matilda') + Book.dahl_objects.count() + +This example also pointed out another interesting technique: using multiple +managers on the same model. You can attach as many ``Manager()`` instances to +a model as you'd like. This is an easy way to define common "filters" for your +models. + +For example:: + + class MaleManager(models.Manager): + def get_query_set(self): + return super(MaleManager, self).get_query_set().filter(sex='M') + + class FemaleManager(models.Manager): + def get_query_set(self): + return super(FemaleManager, self).get_query_set().filter(sex='F') + + class Person(models.Model): + first_name = models.CharField(max_length=50) + last_name = models.CharField(max_length=50) + sex = models.CharField(max_length=1, choices=(('M', 'Male'), ('F', 'Female'))) + people = models.Manager() + men = MaleManager() + women = FemaleManager() + +This example allows you to request ``Person.men.all()``, ``Person.women.all()``, +and ``Person.people.all()``, yielding predictable results. + +If you use custom ``Manager`` objects, take note that the first ``Manager`` +Django encounters (in the order in which they're defined in the model) has a +special status. Django interprets the first ``Manager`` defined in a class as +the "default" ``Manager``, and several parts of Django +(including :djadmin:`dumpdata`) will use that ``Manager`` +exclusively for that model. As a result, it's a good idea to be careful in +your choice of default manager in order to avoid a situation where overriding +``get_query_set()`` results in an inability to retrieve objects you'd like to +work with. + +.. _managers-for-related-objects: + +Using managers for related object access +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +By default, Django uses an instance of a "plain" manager class when accessing +related objects (i.e. ``choice.poll``), not the default manager on the related +object. This is because Django needs to be able to retrieve the related +object, even if it would otherwise be filtered out (and hence be inaccessible) +by the default manager. + +If the normal plain manager class (:class:`django.db.models.Manager`) is not +appropriate for your circumstances, you can force Django to use the same class +as the default manager for your model by setting the `use_for_related_fields` +attribute on the manager class. This is documented fully below_. + +.. _below: manager-types_ + +.. _custom-managers-and-inheritance: + +Custom managers and model inheritance +------------------------------------- + +Class inheritance and model managers aren't quite a perfect match for each +other. Managers are often specific to the classes they are defined on and +inheriting them in subclasses isn't necessarily a good idea. Also, because the +first manager declared is the *default manager*, it is important to allow that +to be controlled. So here's how Django handles custom managers and +:ref:`model inheritance <model-inheritance>`: + + 1. Managers defined on non-abstract base classes are *not* inherited by + child classes. If you want to reuse a manager from a non-abstract base, + redeclare it explicitly on the child class. These sorts of managers are + likely to be fairly specific to the class they are defined on, so + inheriting them can often lead to unexpected results (particularly as + far as the default manager goes). Therefore, they aren't passed onto + child classes. + + 2. Managers from abstract base classes are always inherited by the child + class, using Python's normal name resolution order (names on the child + class override all others; then come names on the first parent class, + and so on). Abstract base classes are designed to capture information + and behavior that is common to their child classes. Defining common + managers is an appropriate part of this common information. + + 3. The default manager on a class is either the first manager declared on + the class, if that exists, or the default manager of the first abstract + base class in the parent hierarchy, if that exists. If no default + manager is explicitly declared, Django's normal default manager is + used. + +These rules provide the necessary flexibility if you want to install a +collection of custom managers on a group of models, via an abstract base +class, but still customize the default manager. For example, suppose you have +this base class:: + + class AbstractBase(models.Model): + ... + objects = CustomManager() + + class Meta: + abstract = True + +If you use this directly in a subclass, ``objects`` will be the default +manager if you declare no managers in the base class:: + + class ChildA(AbstractBase): + ... + # This class has CustomManager as the default manager. + +If you want to inherit from ``AbstractBase``, but provide a different default +manager, you can provide the default manager on the child class:: + + class ChildB(AbstractBase): + ... + # An explicit default manager. + default_manager = OtherManager() + +Here, ``default_manager`` is the default. The ``objects`` manager is +still available, since it's inherited. It just isn't used as the default. + +Finally for this example, suppose you want to add extra managers to the child +class, but still use the default from ``AbstractBase``. You can't add the new +manager directly in the child class, as that would override the default and you would +have to also explicitly include all the managers from the abstract base class. +The solution is to put the extra managers in another base class and introduce +it into the inheritance hierarchy *after* the defaults:: + + class ExtraManager(models.Model): + extra_manager = OtherManager() + + class Meta: + abstract = True + + class ChildC(AbstractBase, ExtraManager): + ... + # Default manager is CustomManager, but OtherManager is + # also available via the "extra_manager" attribute. + +.. _manager-types: + +Controlling Automatic Manager Types +=================================== + +This document has already mentioned a couple of places where Django creates a +manager class for you: `default managers`_ and the "plain" manager used to +`access related objects`_. There are other places in the implementation of +Django where temporary plain managers are needed. Those automatically created +managers will normally be instances of the :class:`django.db.models.Manager` +class. + +.. _default managers: manager-names_ +.. _access related objects: managers-for-related-objects_ + +Throughout this section, we will use the term "automatic manager" to mean a +manager that Django creates for you -- either as a default manager on a model +with no managers, or to use temporarily when accessing related objects. + +Sometimes this default class won't be the right choice. One example is in the +:mod:`django.contrib.gis` application that ships with Django itself. All ``gis`` +models must use a special manager class (:class:`~django.contrib.gis.db.models.GeoManager`) +because they need a special queryset (:class:`~django.contrib.gis.db.models.GeoQuerySet`) +to be used for interacting with the database. It turns out that models which require +a special manager like this need to use the same manager class wherever an automatic +manager is created. + +Django provides a way for custom manager developers to say that their manager +class should be used for automatic managers whenever it is the default manager +on a model. This is done by setting the ``use_for_related_fields`` attribute on +the manager class:: + + class MyManager(models.Manager): + use_for_related_fields = True + + ... + +If this attribute is set on the *default* manager for a model (only the +default manager is considered in these situations), Django will use that class +whenever it needs to automatically create a manager for the class. Otherwise, +it will use :class:`django.db.models.Manager`. + +.. admonition:: Historical Note + + Given the purpose for which it's used, the name of this attribute + (``use_for_related_fields``) might seem a little odd. Originally, the + attribute only controlled the type of manager used for related field + access, which is where the name came from. As it became clear the concept + was more broadly useful, the name hasn't been changed. This is primarily + so that existing code will :doc:`continue to work </misc/api-stability>` in + future Django versions. + +Writing Correct Managers For Use In Automatic Manager Instances +--------------------------------------------------------------- + +As already suggested by the `django.contrib.gis` example, above, the +``use_for_related_fields`` feature is primarily for managers that need to +return a custom ``QuerySet`` subclass. In providing this functionality in your +manager, there are a couple of things to remember. + +Do not filter away any results in this type of manager subclass +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One reason an automatic manager is used is to access objects that are related +to from some other model. In those situations, Django has to be able to see +all the objects for the model it is fetching, so that *anything* which is +referred to can be retrieved. + +If you override the ``get_query_set()`` method and filter out any rows, Django +will return incorrect results. Don't do that. A manager that filters results +in ``get_query_set()`` is not appropriate for use as an automatic manager. + +Set ``use_for_related_fields`` when you define the class +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``use_for_related_fields`` attribute must be set on the manager *class*, +object not on an *instance* of the class. The earlier example shows the +correct way to set it, whereas the following will not work:: + + # BAD: Incorrect code + class MyManager(models.Manager): + ... + + # Sets the attribute on an instance of MyManager. Django will + # ignore this setting. + mgr = MyManager() + mgr.use_for_related_fields = True + + class MyModel(models.Model): + ... + objects = mgr + + # End of incorrect code. + +You also shouldn't change the attribute on the class object after it has been +used in a model, since the attribute's value is processed when the model class +is created and not subsequently reread. Set the attribute on the manager class +when it is first defined, as in the initial example of this section and +everything will work smoothly. + diff --git a/parts/django/docs/topics/db/models.txt b/parts/django/docs/topics/db/models.txt new file mode 100644 index 0000000..2a19cbd --- /dev/null +++ b/parts/django/docs/topics/db/models.txt @@ -0,0 +1,1234 @@ +====== +Models +====== + +.. module:: django.db.models + +A model is the single, definitive source of data about your data. It contains +the essential fields and behaviors of the data you're storing. Generally, each +model maps to a single database table. + +The basics: + + * Each model is a Python class that subclasses + :class:`django.db.models.Model`. + + * Each attribute of the model represents a database field. + + * With all of this, Django gives you an automatically-generated + database-access API; see :doc:`/topics/db/queries`. + +.. seealso:: + + A companion to this document is the `official repository of model + examples`_. (In the Django source distribution, these examples are in the + ``tests/modeltests`` directory.) + + .. _official repository of model examples: http://www.djangoproject.com/documentation/models/ + +Quick example +============= + +This example model defines a ``Person``, which has a ``first_name`` and +``last_name``:: + + from django.db import models + + class Person(models.Model): + first_name = models.CharField(max_length=30) + last_name = models.CharField(max_length=30) + +``first_name`` and ``last_name`` are fields_ of the model. Each field is +specified as a class attribute, and each attribute maps to a database column. + +The above ``Person`` model would create a database table like this: + +.. code-block:: sql + + CREATE TABLE myapp_person ( + "id" serial NOT NULL PRIMARY KEY, + "first_name" varchar(30) NOT NULL, + "last_name" varchar(30) NOT NULL + ); + +Some technical notes: + + * The name of the table, ``myapp_person``, is automatically derived from + some model metadata but can be overridden. See :ref:`table-names` for more + details.. + + * An ``id`` field is added automatically, but this behavior can be + overridden. See :ref:`automatic-primary-key-fields`. + + * The ``CREATE TABLE`` SQL in this example is formatted using PostgreSQL + syntax, but it's worth noting Django uses SQL tailored to the database + backend specified in your :doc:`settings file </topics/settings>`. + +Using models +============ + +Once you have defined your models, you need to tell Django you're going to *use* +those models. Do this by editing your settings file and changing the +:setting:`INSTALLED_APPS` setting to add the name of the module that contains +your ``models.py``. + +For example, if the models for your application live in the module +``mysite.myapp.models`` (the package structure that is created for an +application by the :djadmin:`manage.py startapp <startapp>` script), +:setting:`INSTALLED_APPS` should read, in part:: + + INSTALLED_APPS = ( + #... + 'mysite.myapp', + #... + ) + +When you add new apps to :setting:`INSTALLED_APPS`, be sure to run +:djadmin:`manage.py syncdb <syncdb>`. + +Fields +====== + +The most important part of a model -- and the only required part of a model -- +is the list of database fields it defines. Fields are specified by class +attributes. + +Example:: + + class Musician(models.Model): + first_name = models.CharField(max_length=50) + last_name = models.CharField(max_length=50) + instrument = models.CharField(max_length=100) + + class Album(models.Model): + artist = models.ForeignKey(Musician) + name = models.CharField(max_length=100) + release_date = models.DateField() + num_stars = models.IntegerField() + +Field types +----------- + +Each field in your model should be an instance of the appropriate +:class:`~django.db.models.Field` class. Django uses the field class types to +determine a few things: + + * The database column type (e.g. ``INTEGER``, ``VARCHAR``). + + * The :doc:`widget </ref/forms/widgets>` to use in Django's admin interface, + if you care to use it (e.g. ``<input type="text">``, ``<select>``). + + * The minimal validation requirements, used in Django's admin and in + automatically-generated forms. + +Django ships with dozens of built-in field types; you can find the complete list +in the :ref:`model field reference <model-field-types>`. You can easily write +your own fields if Django's built-in ones don't do the trick; see +:doc:`/howto/custom-model-fields`. + +Field options +------------- + +Each field takes a certain set of field-specific arguments (documented in the +:ref:`model field reference <model-field-types>`). For example, +:class:`~django.db.models.CharField` (and its subclasses) require a +:attr:`~django.db.models.CharField.max_length` argument which specifies the size +of the ``VARCHAR`` database field used to store the data. + +There's also a set of common arguments available to all field types. All are +optional. They're fully explained in the :ref:`reference +<common-model-field-options>`, but here's a quick summary of the most often-used +ones: + + :attr:`~Field.null` + If ``True``, Django will store empty values as ``NULL`` in the database. + Default is ``False``. + + :attr:`~Field.blank` + If ``True``, the field is allowed to be blank. Default is ``False``. + + Note that this is different than :attr:`~Field.null`. + :attr:`~Field.null` is purely database-related, whereas + :attr:`~Field.blank` is validation-related. If a field has + :attr:`blank=True <Field.blank>`, validation on Django's admin site will + allow entry of an empty value. If a field has :attr:`blank=False + <Field.blank>`, the field will be required. + + :attr:`~Field.choices` + An iterable (e.g., a list or tuple) of 2-tuples to use as choices for + this field. If this is given, Django's admin will use a select box + instead of the standard text field and will limit choices to the choices + given. + + 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'), + ) + + The first element in each tuple is the value that will be stored in the + database, the second element will be displayed by the admin interface, + or in a ModelChoiceField. Given an instance of a model object, the + display value for a choices field can be accessed using the + ``get_FOO_display`` method. For example:: + + from django.db import models + + class Person(models.Model): + GENDER_CHOICES = ( + (u'M', u'Male'), + (u'F', u'Female'), + ) + name = models.CharField(max_length=60) + gender = models.CharField(max_length=2, choices=GENDER_CHOICES) + + :: + + >>> p = Person(name="Fred Flinstone", gender="M") + >>> p.save() + >>> p.gender + u'M' + >>> p.get_gender_display() + u'Male' + + :attr:`~Field.default` + The default value for the field. This can be a value or a callable + object. If callable it will be called every time a new object is + created. + + :attr:`~Field.help_text` + Extra "help" text to be displayed under the field on the object's admin + form. It's useful for documentation even if your object doesn't have an + admin form. + + :attr:`~Field.primary_key` + If ``True``, this field is the primary key for the model. + + If you don't specify :attr:`primary_key=True <Field.primary_key>` for + any fields in your model, Django will automatically add an + :class:`IntegerField` to hold the primary key, so you don't need to set + :attr:`primary_key=True <Field.primary_key>` on any of your fields + unless you want to override the default primary-key behavior. For more, + see :ref:`automatic-primary-key-fields`. + + :attr:`~Field.unique` + If ``True``, this field must be unique throughout the table. + +Again, these are just short descriptions of the most common field options. Full +details can be found in the :ref:`common model field option reference +<common-model-field-options>`. + +.. _automatic-primary-key-fields: + +Automatic primary key fields +---------------------------- + +By default, Django gives each model the following field:: + + id = models.AutoField(primary_key=True) + +This is an auto-incrementing primary key. + +If you'd like to specify a custom primary key, just specify +:attr:`primary_key=True <Field.primary_key>` on one of your fields. If Django +sees you've explicitly set :attr:`Field.primary_key`, it won't add the automatic +``id`` column. + +Each model requires exactly one field to have :attr:`primary_key=True +<Field.primary_key>`. + +.. _verbose-field-names: + +Verbose field names +------------------- + +Each field type, except for :class:`~django.db.models.ForeignKey`, +:class:`~django.db.models.ManyToManyField` and +:class:`~django.db.models.OneToOneField`, takes an optional first positional +argument -- a verbose name. If the verbose name isn't given, Django will +automatically create it using the field's attribute name, converting underscores +to spaces. + +In this example, the verbose name is ``"person's first name"``:: + + first_name = models.CharField("person's first name", max_length=30) + +In this example, the verbose name is ``"first name"``:: + + first_name = models.CharField(max_length=30) + +:class:`~django.db.models.ForeignKey`, +:class:`~django.db.models.ManyToManyField` and +:class:`~django.db.models.OneToOneField` require the first argument to be a +model class, so use the :attr:`~Field.verbose_name` keyword argument:: + + poll = models.ForeignKey(Poll, verbose_name="the related poll") + sites = models.ManyToManyField(Site, verbose_name="list of sites") + place = models.OneToOneField(Place, verbose_name="related place") + +The convention is not to capitalize the first letter of the +:attr:`~Field.verbose_name`. Django will automatically capitalize the first +letter where it needs to. + +Relationships +------------- + +Clearly, the power of relational databases lies in relating tables to each +other. Django offers ways to define the three most common types of database +relationships: many-to-one, many-to-many and one-to-one. + +Many-to-one relationships +~~~~~~~~~~~~~~~~~~~~~~~~~ + +To define a many-to-one relationship, use :class:`~django.db.models.ForeignKey`. +You use it just like any other :class:`~django.db.models.Field` type: by +including it as a class attribute of your model. + +:class:`~django.db.models.ForeignKey` requires a positional argument: the class +to which the model is related. + +For example, if a ``Car`` model has a ``Manufacturer`` -- that is, a +``Manufacturer`` makes multiple cars but each ``Car`` only has one +``Manufacturer`` -- use the following definitions:: + + class Manufacturer(models.Model): + # ... + + class Car(models.Model): + manufacturer = models.ForeignKey(Manufacturer) + # ... + +You can also create :ref:`recursive relationships <recursive-relationships>` (an +object with a many-to-one relationship to itself) and :ref:`relationships to +models not yet defined <lazy-relationships>`; see :ref:`the model field +reference <ref-foreignkey>` for details. + +It's suggested, but not required, that the name of a +:class:`~django.db.models.ForeignKey` field (``manufacturer`` in the example +above) be the name of the model, lowercase. You can, of course, call the field +whatever you want. For example:: + + class Car(models.Model): + company_that_makes_it = models.ForeignKey(Manufacturer) + # ... + +.. seealso:: + + See the `Many-to-one relationship model example`_ for a full example. + +.. _Many-to-one relationship model example: http://www.djangoproject.com/documentation/models/many_to_one/ + +:class:`~django.db.models.ForeignKey` fields also accept a number of extra +arguments which are explained in :ref:`the model field reference +<foreign-key-arguments>`. These options help define how the relationship should +work; all are optional. + +Many-to-many relationships +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To define a many-to-many relationship, use +:class:`~django.db.models.ManyToManyField`. You use it just like any other +:class:`~django.db.models.Field` type: by including it as a class attribute of +your model. + +:class:`~django.db.models.ManyToManyField` requires a positional argument: the +class to which the model is related. + +For example, if a ``Pizza`` has multiple ``Topping`` objects -- that is, a +``Topping`` can be on multiple pizzas and each ``Pizza`` has multiple toppings +-- here's how you'd represent that:: + + class Topping(models.Model): + # ... + + class Pizza(models.Model): + # ... + toppings = models.ManyToManyField(Topping) + +As with :class:`~django.db.models.ForeignKey`, you can also create +:ref:`recursive relationships <recursive-relationships>` (an object with a +many-to-many relationship to itself) and :ref:`relationships to models not yet +defined <lazy-relationships>`; see :ref:`the model field reference +<ref-manytomany>` for details. + +It's suggested, but not required, that the name of a +:class:`~django.db.models.ManyToManyField` (``toppings`` in the example above) +be a plural describing the set of related model objects. + +It doesn't matter which model gets the +:class:`~django.db.models.ManyToManyField`, but you only need it in one of the +models -- not in both. + +Generally, :class:`~django.db.models.ManyToManyField` instances should go in the +object that's going to be edited in the admin interface, if you're using +Django's admin. In the above example, ``toppings`` is in ``Pizza`` (rather than +``Topping`` having a ``pizzas`` :class:`~django.db.models.ManyToManyField` ) +because it's more natural to think about a pizza having toppings than a +topping being on multiple pizzas. The way it's set up above, the ``Pizza`` admin +form would let users select the toppings. + +.. seealso:: + + See the `Many-to-many relationship model example`_ for a full example. + +.. _Many-to-many relationship model example: http://www.djangoproject.com/documentation/models/many_to_many/ + +:class:`~django.db.models.ManyToManyField` fields also accept a number of extra +arguments which are explained in :ref:`the model field reference +<manytomany-arguments>`. These options help define how the relationship should +work; all are optional. + +.. _intermediary-manytomany: + +Extra fields on many-to-many relationships +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.0 + +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 +you may need to associate data with the relationship between two models. + +For example, consider the case of an application tracking the musical groups +which musicians belong to. There is a many-to-many relationship between a person +and the groups of which they are a member, so you could use a +:class:`~django.db.models.ManyToManyField` to represent this relationship. +However, there is a lot of detail about the membership that you might want to +collect, such as the date at which the person joined the group. + +For these situations, Django allows you to specify the model that will be used +to govern the many-to-many relationship. You can then put extra fields on the +intermediate model. The intermediate model is associated with the +:class:`~django.db.models.ManyToManyField` using the +:attr:`through <ManyToManyField.through>` argument to point to the model +that will act as an intermediary. For our musician example, the code would look +something like this:: + + class Person(models.Model): + name = models.CharField(max_length=128) + + def __unicode__(self): + return self.name + + class Group(models.Model): + name = models.CharField(max_length=128) + members = models.ManyToManyField(Person, through='Membership') + + def __unicode__(self): + return self.name + + class Membership(models.Model): + person = models.ForeignKey(Person) + group = models.ForeignKey(Group) + date_joined = models.DateField() + invite_reason = models.CharField(max_length=64) + +When you set up the intermediary model, you explicitly specify foreign +keys to the models that are involved in the ManyToMany relation. This +explicit declaration defines how the two models are related. + +There are a few restrictions on the intermediate model: + + * Your intermediate model must contain one - and *only* one - foreign key + to the target model (this would be ``Person`` in our example). If you + have more than one foreign key, a validation error will be raised. + + * Your intermediate model must contain one - and *only* one - foreign key + to the source model (this would be ``Group`` in our example). If you + have more than one foreign key, a validation error will be raised. + + * The only exception to this is a model which has a many-to-many + relationship to itself, through an intermediary model. In this + case, two foreign keys to the same model are permitted, but they + will be treated as the two (different) sides of the many-to-many + relation. + + * When defining a many-to-many relationship from a model to + itself, using an intermediary model, you *must* use + :attr:`symmetrical=False <ManyToManyField.symmetrical>` (see + :ref:`the model field reference <manytomany-arguments>`). + +Now that you have set up your :class:`~django.db.models.ManyToManyField` to use +your intermediary model (``Membership``, in this case), you're ready to start +creating some many-to-many relationships. You do this by creating instances of +the intermediate model:: + + >>> ringo = Person.objects.create(name="Ringo Starr") + >>> paul = Person.objects.create(name="Paul McCartney") + >>> beatles = Group.objects.create(name="The Beatles") + >>> m1 = Membership(person=ringo, group=beatles, + ... date_joined=date(1962, 8, 16), + ... invite_reason= "Needed a new drummer.") + >>> m1.save() + >>> beatles.members.all() + [<Person: Ringo Starr>] + >>> ringo.group_set.all() + [<Group: The Beatles>] + >>> m2 = Membership.objects.create(person=paul, group=beatles, + ... date_joined=date(1960, 8, 1), + ... invite_reason= "Wanted to form a band.") + >>> beatles.members.all() + [<Person: Ringo Starr>, <Person: Paul McCartney>] + +Unlike normal many-to-many fields, you *can't* use ``add``, ``create``, +or assignment (i.e., ``beatles.members = [...]``) to create relationships:: + + # THIS WILL NOT WORK + >>> beatles.members.add(john) + # NEITHER WILL THIS + >>> beatles.members.create(name="George Harrison") + # AND NEITHER WILL THIS + >>> beatles.members = [john, paul, ringo, george] + +Why? You can't just create a relationship between a ``Person`` and a ``Group`` +- you need to specify all the detail for the relationship required by the +``Membership`` model. The simple ``add``, ``create`` and assignment calls +don't provide a way to specify this extra detail. As a result, they are +disabled for many-to-many relationships that use an intermediate model. +The only way to create this type of relationship is to create instances of the +intermediate model. + +The :meth:`~django.db.models.fields.related.RelatedManager.remove` method is +disabled for similar reasons. However, the +:meth:`~django.db.models.fields.related.RelatedManager.clear` method can be +used to remove all many-to-many relationships for an instance:: + + # Beatles have broken up + >>> beatles.members.clear() + +Once you have established the many-to-many relationships by creating instances +of your intermediate model, you can issue queries. Just as with normal +many-to-many relationships, you can query using the attributes of the +many-to-many-related model:: + + # Find all the groups with a member whose name starts with 'Paul' + >>> Group.objects.filter(members__name__startswith='Paul') + [<Group: The Beatles>] + +As you are using an intermediate model, you can also query on its attributes:: + + # Find all the members of the Beatles that joined after 1 Jan 1961 + >>> Person.objects.filter( + ... group__name='The Beatles', + ... membership__date_joined__gt=date(1961,1,1)) + [<Person: Ringo Starr] + + +One-to-one relationships +~~~~~~~~~~~~~~~~~~~~~~~~ + +To define a one-to-one relationship, use +:class:`~django.db.models.OneToOneField`. You use it just like any other +``Field`` type: by including it as a class attribute of your model. + +This is most useful on the primary key of an object when that object "extends" +another object in some way. + +:class:`~django.db.models.OneToOneField` requires a positional argument: the +class to which the model is related. + +For example, if you were building a database of "places", you would +build pretty standard stuff such as address, phone number, etc. in the +database. Then, if you wanted to build a database of restaurants on +top of the places, instead of repeating yourself and replicating those +fields in the ``Restaurant`` model, you could make ``Restaurant`` have +a :class:`~django.db.models.OneToOneField` to ``Place`` (because a +restaurant "is a" place; in fact, to handle this you'd typically use +:ref:`inheritance <model-inheritance>`, which involves an implicit +one-to-one relation). + +As with :class:`~django.db.models.ForeignKey`, a +:ref:`recursive relationship <recursive-relationships>` +can be defined and +:ref:`references to as-yet undefined models <lazy-relationships>` +can be made; see :ref:`the model field reference <ref-onetoone>` for details. + +.. seealso:: + + See the `One-to-one relationship model example`_ for a full example. + +.. _One-to-one relationship model example: http://www.djangoproject.com/documentation/models/one_to_one/ + +.. versionadded:: 1.0 + +:class:`~django.db.models.OneToOneField` fields also accept one optional argument +described in the :ref:`model field reference <ref-onetoone>`. + +:class:`~django.db.models.OneToOneField` classes used to automatically become +the primary key on a model. This is no longer true (although you can manually +pass in the :attr:`~django.db.models.Field.primary_key` argument if you like). +Thus, it's now possible to have multiple fields of type +:class:`~django.db.models.OneToOneField` on a single model. + +Models across files +------------------- + +It's perfectly OK to relate a model to one from another app. To do this, +import the related model at the top of the model that holds your model. Then, +just refer to the other model class wherever needed. For example:: + + from geography.models import ZipCode + + class Restaurant(models.Model): + # ... + zip_code = models.ForeignKey(ZipCode) + +Field name restrictions +----------------------- + +Django places only two restrictions on model field names: + + 1. A field name cannot be a Python reserved word, because that would result + in a Python syntax error. For example:: + + class Example(models.Model): + pass = models.IntegerField() # 'pass' is a reserved word! + + 2. A field name cannot contain more than one underscore in a row, due to + the way Django's query lookup syntax works. For example:: + + class Example(models.Model): + foo__bar = models.IntegerField() # 'foo__bar' has two underscores! + +These limitations can be worked around, though, because your field name doesn't +necessarily have to match your database column name. See the +:attr:`~Field.db_column` option. + +SQL reserved words, such as ``join``, ``where`` or ``select``, *are* allowed as +model field names, because Django escapes all database table names and column +names in every underlying SQL query. It uses the quoting syntax of your +particular database engine. + +Custom field types +------------------ + +.. versionadded:: 1.0 + +If one of the existing model fields cannot be used to fit your purposes, or if +you wish to take advantage of some less common database column types, you can +create your own field class. Full coverage of creating your own fields is +provided in :doc:`/howto/custom-model-fields`. + +.. _meta-options: + +Meta options +============ + +Give your model metadata by using an inner ``class Meta``, like so:: + + class Ox(models.Model): + horn_length = models.IntegerField() + + class Meta: + ordering = ["horn_length"] + verbose_name_plural = "oxen" + +Model metadata is "anything that's not a field", such as ordering options +(:attr:`~Options.ordering`), database table name (:attr:`~Options.db_table`), or +human-readable singular and plural names (:attr:`~Options.verbose_name` and +:attr:`~Options.verbose_name_plural`). None are required, and adding ``class +Meta`` to a model is completely optional. + +A complete list of all possible ``Meta`` options can be found in the :doc:`model +option reference </ref/models/options>`. + +.. _model-methods: + +Model methods +============= + +Define custom methods on a model to add custom "row-level" functionality to your +objects. Whereas :class:`~django.db.models.Manager` methods are intended to do +"table-wide" things, model methods should act on a particular model instance. + +This is a valuable technique for keeping business logic in one place -- the +model. + +For example, this model has a few custom methods:: + + from django.contrib.localflavor.us.models import USStateField + + class Person(models.Model): + first_name = models.CharField(max_length=50) + last_name = models.CharField(max_length=50) + birth_date = models.DateField() + address = models.CharField(max_length=100) + city = models.CharField(max_length=50) + state = USStateField() # Yes, this is America-centric... + + def baby_boomer_status(self): + "Returns the person's baby-boomer status." + import datetime + if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12, 31): + return "Baby boomer" + if self.birth_date < datetime.date(1945, 8, 1): + return "Pre-boomer" + return "Post-boomer" + + def is_midwestern(self): + "Returns True if this person is from the Midwest." + return self.state in ('IL', 'WI', 'MI', 'IN', 'OH', 'IA', 'MO') + + def _get_full_name(self): + "Returns the person's full name." + return '%s %s' % (self.first_name, self.last_name) + full_name = property(_get_full_name) + +The last method in this example is a :term:`property`. `Read more about +properties`_. + +.. _Read more about properties: http://www.python.org/download/releases/2.2/descrintro/#property + +The :doc:`model instance reference </ref/models/instances>` has a complete list +of :ref:`methods automatically given to each model <model-instance-methods>`. +You can override most of these -- see `overriding predefined model methods`_, +below -- but there are a couple that you'll almost always want to define: + + :meth:`~Model.__unicode__` + A Python "magic method" that returns a unicode "representation" of any + object. This is what Python and Django will use whenever a model + instance needs to be coerced and displayed as a plain string. Most + notably, this happens when you display an object in an interactive + console or in the admin. + + You'll always want to define this method; the default isn't very helpful + at all. + + :meth:`~Model.get_absolute_url` + This tells Django how to calculate the URL for an object. Django uses + this in its admin interface, and any time it needs to figure out a URL + for an object. + + Any object that has a URL that uniquely identifies it should define this + method. + +.. _overriding-model-methods: + +Overriding predefined model methods +----------------------------------- + +There's another set of :ref:`model methods <model-instance-methods>` that +encapsulate a bunch of database behavior that you'll want to customize. In +particular you'll often want to change the way :meth:`~Model.save` and +:meth:`~Model.delete` work. + +You're free to override these methods (and any other model method) to alter +behavior. + +A classic use-case for overriding the built-in methods is if you want something +to happen whenever you save an object. For example (see +:meth:`~Model.save` for documentation of the parameters it accepts):: + + class Blog(models.Model): + name = models.CharField(max_length=100) + tagline = models.TextField() + + def save(self, *args, **kwargs): + do_something() + super(Blog, self).save(*args, **kwargs) # Call the "real" save() method. + do_something_else() + +You can also prevent saving:: + + class Blog(models.Model): + name = models.CharField(max_length=100) + tagline = models.TextField() + + def save(self, *args, **kwargs): + if self.name == "Yoko Ono's blog": + return # Yoko shall never have her own blog! + else: + super(Blog, self).save(*args, **kwargs) # Call the "real" save() method. + +It's important to remember to call the superclass method -- that's +that ``super(Blog, self).save(*args, **kwargs)`` business -- to ensure +that the object still gets saved into the database. If you forget to +call the superclass method, the default behavior won't happen and the +database won't get touched. + +It's also important that you pass through the arguments that can be +passed to the model method -- that's what the ``*args, **kwargs`` bit +does. Django will, from time to time, extend the capabilities of +built-in model methods, adding new arguments. If you use ``*args, +**kwargs`` in your method definitions, you are guaranteed that your +code will automatically support those arguments when they are added. + +Executing custom SQL +-------------------- + +Another common pattern is writing custom SQL statements in model methods and +module-level methods. For more details on using raw SQL, see the documentation +on :doc:`using raw SQL</topics/db/sql>`. + +.. _model-inheritance: + +Model inheritance +================= + +.. versionadded:: 1.0 + +Model inheritance in Django works almost identically to the way normal +class inheritance works in Python. The only decision you have to make +is whether you want the parent models to be models in their own right +(with their own database tables), or if the parents are just holders +of common information that will only be visible through the child +models. + +There are three styles of inheritance that are possible in Django. + + 1. Often, you will just want to use the parent class to hold information that + you don't want to have to type out for each child model. This class isn't + going to ever be used in isolation, so :ref:`abstract-base-classes` are + what you're after. + 2. If you're subclassing an existing model (perhaps something from another + application entirely) and want each model to have its own database table, + :ref:`multi-table-inheritance` is the way to go. + 3. Finally, if you only want to modify the Python-level behaviour of a model, + without changing the models fields in any way, you can use + :ref:`proxy-models`. + +.. _abstract-base-classes: + +Abstract base classes +--------------------- + +Abstract base classes are useful when you want to put some common +information into a number of other models. You write your base class +and put ``abstract=True`` in the :ref:`Meta <meta-options>` +class. This model will then not be used to create any database +table. Instead, when it is used as a base class for other models, its +fields will be added to those of the child class. It is an error to +have fields in the abstract base class with the same name as those in +the child (and Django will raise an exception). + +An example:: + + class CommonInfo(models.Model): + name = models.CharField(max_length=100) + age = models.PositiveIntegerField() + + class Meta: + abstract = True + + class Student(CommonInfo): + home_group = models.CharField(max_length=5) + +The ``Student`` model will have three fields: ``name``, ``age`` and +``home_group``. The ``CommonInfo`` model cannot be used as a normal Django +model, since it is an abstract base class. It does not generate a database +table or have a manager, and cannot be instantiated or saved directly. + +For many uses, this type of model inheritance will be exactly what you want. +It provides a way to factor out common information at the Python level, whilst +still only creating one database table per child model at the database level. + +``Meta`` inheritance +~~~~~~~~~~~~~~~~~~~~ + +When an abstract base class is created, Django makes any :ref:`Meta <meta-options>` +inner class you declared in the base class available as an +attribute. If a child class does not declare its own :ref:`Meta <meta-options>` +class, it will inherit the parent's :ref:`Meta <meta-options>`. If the child wants to +extend the parent's :ref:`Meta <meta-options>` class, it can subclass it. For example:: + + class CommonInfo(models.Model): + ... + class Meta: + abstract = True + ordering = ['name'] + + class Student(CommonInfo): + ... + class Meta(CommonInfo.Meta): + db_table = 'student_info' + +Django does make one adjustment to the :ref:`Meta <meta-options>` class of an abstract base +class: before installing the :ref:`Meta <meta-options>` attribute, it sets ``abstract=False``. +This means that children of abstract base classes don't automatically become +abstract classes themselves. Of course, you can make an abstract base class +that inherits from another abstract base class. You just need to remember to +explicitly set ``abstract=True`` each time. + +Some attributes won't make sense to include in the :ref:`Meta <meta-options>` class of an +abstract base class. For example, including ``db_table`` would mean that all +the child classes (the ones that don't specify their own :ref:`Meta <meta-options>`) would use +the same database table, which is almost certainly not what you want. + +.. _abstract-related-name: + +Be careful with ``related_name`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you are using the :attr:`~django.db.models.ForeignKey.related_name` attribute on a ``ForeignKey`` or +``ManyToManyField``, you must always specify a *unique* reverse name for the +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'``. + +- ``'%(class)s'`` is replaced by the lower-cased name of the child class + that the field is used in. +- ``'%(app_label)s'`` is replaced by the lower-cased name of the app the child + class is contained within. Each installed application name must be unique + and the model class names within each app must also be unique, therefore the + resulting name will end up being different. + +For example, given an app ``common/models.py``:: + + class Base(models.Model): + m2m = models.ManyToManyField(OtherModel, related_name="%(app_label)s_%(class)s_related") + + class Meta: + abstract = True + + class ChildA(Base): + pass + + class ChildB(Base): + pass + +Along with another app ``rare/models.py``:: + + from common.models import Base + + class ChildB(Base): + pass + +The reverse name of the ``commmon.ChildA.m2m`` field will be +``common_childa_related``, whilst the reverse name of the +``common.ChildB.m2m`` field will be ``common_childb_related``, and finally the +reverse name of the ``rare.ChildB.m2m`` field will be ``rare_childb_related``. +It is up to you how you use the ``'%(class)s'`` and ``'%(app_label)s`` portion +to construct your related name, but if you forget to use it, Django will raise +errors when you validate your models (or run :djadmin:`syncdb`). + +If you don't specify a :attr:`~django.db.models.ForeignKey.related_name` +attribute for a field in an abstract base class, the default reverse name will +be the name of the child class followed by ``'_set'``, just as it normally +would be if you'd declared the field directly on the child class. For example, +in the above code, if the :attr:`~django.db.models.ForeignKey.related_name` +attribute was omitted, the reverse name for the ``m2m`` field would be +``childa_set`` in the ``ChildA`` case and ``childb_set`` for the ``ChildB`` +field. + +.. _multi-table-inheritance: + +Multi-table inheritance +----------------------- + +The second type of model inheritance supported by Django is when each model in +the hierarchy is a model all by itself. Each model corresponds to its own +database table and can be queried and created individually. The inheritance +relationship introduces links between the child model and each of its parents +(via an automatically-created :class:`~django.db.models.fields.OneToOneField`). +For example:: + + class Place(models.Model): + name = models.CharField(max_length=50) + address = models.CharField(max_length=80) + + class Restaurant(Place): + serves_hot_dogs = models.BooleanField() + serves_pizza = models.BooleanField() + +All of the fields of ``Place`` will also be available in ``Restaurant``, +although the data will reside in a different database table. So these are both +possible:: + + >>> Place.objects.filter(name="Bob's Cafe") + >>> Restaurant.objects.filter(name="Bob's Cafe") + +If you have a ``Place`` that is also a ``Restaurant``, you can get from the +``Place`` object to the ``Restaurant`` object by using the lower-case version +of the model name:: + + >>> p = Place.objects.get(id=12) + # If p is a Restaurant object, this will give the child class: + >>> p.restaurant + <Restaurant: ...> + +However, if ``p`` in the above example was *not* a ``Restaurant`` (it had been +created directly as a ``Place`` object or was the parent of some other class), +referring to ``p.restaurant`` would raise a Restaurant.DoesNotExist exception. + +``Meta`` and multi-table inheritance +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the multi-table inheritance situation, it doesn't make sense for a child +class to inherit from its parent's :ref:`Meta <meta-options>` class. All the :ref:`Meta <meta-options>` options +have already been applied to the parent class and applying them again would +normally only lead to contradictory behavior (this is in contrast with the +abstract base class case, where the base class doesn't exist in its own +right). + +So a child model does not have access to its parent's :ref:`Meta +<meta-options>` class. However, there are a few limited cases where the child +inherits behavior from the parent: if the child does not specify an +:attr:`~django.db.models.Options.ordering` attribute or a +:attr:`~django.db.models.Options.get_latest_by` attribute, it will inherit +these from its parent. + +If the parent has an ordering and you don't want the child to have any natural +ordering, you can explicitly disable it:: + + class ChildModel(ParentModel): + ... + class Meta: + # Remove parent's ordering effect + ordering = [] + +Inheritance and reverse relations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Because multi-table inheritance uses an implicit +:class:`~django.db.models.OneToOneField` to link the child and +the parent, it's possible to move from the parent down to the child, +as in the above example. However, this uses up the name that is the +default :attr:`~django.db.models.ForeignKey.related_name` value for +:class:`~django.db.models.ForeignKey` and +:class:`~django.db.models.ManyToManyField` relations. If you +are putting those types of relations on a subclass of another model, +you **must** specify the +:attr:`~django.db.models.ForeignKey.related_name` attribute on each +such field. If you forget, Django will raise an error when you run +:djadmin:`validate` or :djadmin:`syncdb`. + +For example, using the above ``Place`` class again, let's create another +subclass with a :class:`~django.db.models.ManyToManyField`:: + + class Supplier(Place): + # Must specify related_name on all relations. + customers = models.ManyToManyField(Restaurant, related_name='provider') + + +Specifying the parent link field +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As mentioned, Django will automatically create a +:class:`~django.db.models.OneToOneField` linking your child +class back any non-abstract parent models. If you want to control the +name of the attribute linking back to the parent, you can create your +own :class:`~django.db.models.OneToOneField` and set +:attr:`parent_link=True <django.db.models.OneToOneField.parent_link>` +to indicate that your field is the link back to the parent class. + +.. _proxy-models: + +Proxy models +------------ + +.. versionadded:: 1.1 + +When using :ref:`multi-table inheritance <multi-table-inheritance>`, a new +database table is created for each subclass of a model. This is usually the +desired behavior, since the subclass needs a place to store any additional +data fields that are not present on the base class. Sometimes, however, you +only want to change the Python behavior of a model -- perhaps to change the +default manager, or add a new method. + +This is what proxy model inheritance is for: creating a *proxy* for the +original model. You can create, delete and update instances of the proxy model +and all the data will be saved as if you were using the original (non-proxied) +model. The difference is that you can change things like the default model +ordering or the default manager in the proxy, without having to alter the +original. + +Proxy models are declared like normal models. You tell Django that it's a +proxy model by setting the :attr:`~django.db.models.Options.proxy` attribute of +the ``Meta`` class to ``True``. + +For example, suppose you want to add a method to the standard +:class:`~django.contrib.auth.models.User` model that will be used in your +templates. You can do it like this:: + + from django.contrib.auth.models import User + + class MyUser(User): + class Meta: + proxy = True + + def do_something(self): + ... + +The ``MyUser`` class operates on the same database table as its parent +:class:`~django.contrib.auth.models.User` class. In particular, any new +instances of :class:`~django.contrib.auth.models.User` will also be accessible +through ``MyUser``, and vice-versa:: + + >>> u = User.objects.create(username="foobar") + >>> MyUser.objects.get(username="foobar") + <MyUser: foobar> + +You could also use a proxy model to define a different default ordering on a +model. The standard :class:`~django.contrib.auth.models.User` model has no +ordering defined on it (intentionally; sorting is expensive and we don't want +to do it all the time when we fetch users). You might want to regularly order +by the ``username`` attribute when you use the proxy. This is easy:: + + class OrderedUser(User): + class Meta: + ordering = ["username"] + proxy = True + +Now normal :class:`~django.contrib.auth.models.User` queries will be unordered +and ``OrderedUser`` queries will be ordered by ``username``. + +QuerySets still return the model that was requested +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There is no way to have Django return, say, a ``MyUser`` object whenever you +query for :class:`~django.contrib.auth.models.User` objects. A queryset for +``User`` objects will return those types of objects. The whole point of proxy +objects is that code relying on the original ``User`` will use those and your +own code can use the extensions you included (that no other code is relying on +anyway). It is not a way to replace the ``User`` (or any other) model +everywhere with something of your own creation. + +Base class restrictions +~~~~~~~~~~~~~~~~~~~~~~~ + +A proxy model must inherit from exactly one non-abstract model class. You +can't inherit from multiple non-abstract models as the proxy model doesn't +provide any connection between the rows in the different database tables. A +proxy model can inherit from any number of abstract model classes, providing +they do *not* define any model fields. + +Proxy models inherit any ``Meta`` options that they don't define from their +non-abstract model parent (the model they are proxying for). + +Proxy model managers +~~~~~~~~~~~~~~~~~~~~ + +If you don't specify any model managers on a proxy model, it inherits the +managers from its model parents. If you define a manager on the proxy model, +it will become the default, although any managers defined on the parent +classes will still be available. + +Continuing our example from above, you could change the default manager used +when you query the ``User`` model like this:: + + class NewManager(models.Manager): + ... + + class MyUser(User): + objects = NewManager() + + class Meta: + proxy = True + +If you wanted to add a new manager to the Proxy, without replacing the +existing default, you can use the techniques described in the :ref:`custom +manager <custom-managers-and-inheritance>` documentation: create a base class +containing the new managers and inherit that after the primary base class:: + + # Create an abstract class for the new manager. + class ExtraManagers(models.Model): + secondary = NewManager() + + class Meta: + abstract = True + + class MyUser(User, ExtraManagers): + class Meta: + proxy = True + +You probably won't need to do this very often, but, when you do, it's +possible. + +.. _proxy-vs-unmanaged-models: + +Differences between proxy inheritance and unmanaged models +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Proxy model inheritance might look fairly similar to creating an unmanaged +model, using the :attr:`~django.db.models.Options.managed` attribute on a +model's ``Meta`` class. The two alternatives are not quite the same and it's +worth considering which one you should use. + +One difference is that you can (and, in fact, must unless you want an empty +model) specify model fields on models with ``Meta.managed=False``. You could, +with careful setting of :attr:`Meta.db_table +<django.db.models.Options.db_table>` create an unmanaged model that shadowed +an existing model and add Python methods to it. However, that would be very +repetitive and fragile as you need to keep both copies synchronized if you +make any changes. + +The other difference that is more important for proxy models, is how model +managers are handled. Proxy models are intended to behave exactly like the +model they are proxying for. So they inherit the parent model's managers, +including the default manager. In the normal multi-table model inheritance +case, children do not inherit managers from their parents as the custom +managers aren't always appropriate when extra fields are involved. The +:ref:`manager documentation <custom-managers-and-inheritance>` has more +details about this latter case. + +When these two features were implemented, attempts were made to squash them +into a single option. It turned out that interactions with inheritance, in +general, and managers, in particular, made the API very complicated and +potentially difficult to understand and use. It turned out that two options +were needed in any case, so the current separation arose. + +So, the general rules are: + + 1. If you are mirroring an existing model or database table and don't want + all the original database table columns, use ``Meta.managed=False``. + That option is normally useful for modeling database views and tables + not under the control of Django. + 2. If you are wanting to change the Python-only behavior of a model, but + keep all the same fields as in the original, use ``Meta.proxy=True``. + This sets things up so that the proxy model is an exact copy of the + storage structure of the original model when data is saved. + +Multiple inheritance +-------------------- + +Just as with Python's subclassing, it's possible for a Django model to inherit +from multiple parent models. Keep in mind that normal Python name resolution +rules apply. The first base class that a particular name (e.g. :ref:`Meta +<meta-options>`) appears in will be the one that is used; for example, this +means that if multiple parents contain a :ref:`Meta <meta-options>` class, +only the first one is going to be used, and all others will be ignored. + +Generally, you won't need to inherit from multiple parents. The main use-case +where this is useful is for "mix-in" classes: adding a particular extra +field or method to every class that inherits the mix-in. Try to keep your +inheritance hierarchies as simple and straightforward as possible so that you +won't have to struggle to work out where a particular piece of information is +coming from. + +Field name "hiding" is not permitted +------------------------------------- + +In normal Python class inheritance, it is permissible for a child class to +override any attribute from the parent class. In Django, this is not permitted +for attributes that are :class:`~django.db.models.fields.Field` instances (at +least, not at the moment). If a base class has a field called ``author``, you +cannot create another model field called ``author`` in any class that inherits +from that base class. + +Overriding fields in a parent model leads to difficulties in areas such as +initialising new instances (specifying which field is being initialized in +``Model.__init__``) and serialization. These are features which normal Python +class inheritance doesn't have to deal with in quite the same way, so the +difference between Django model inheritance and Python class inheritance isn't +arbitrary. + +This restriction only applies to attributes which are +:class:`~django.db.models.fields.Field` instances. Normal Python attributes +can be overridden if you wish. It also only applies to the name of the +attribute as Python sees it: if you are manually specifying the database +column name, you can have the same column name appearing in both a child and +an ancestor model for multi-table inheritance (they are columns in two +different database tables). + +Django will raise a :exc:`~django.core.exceptions.FieldError` if you override +any model field in any ancestor model. diff --git a/parts/django/docs/topics/db/multi-db.txt b/parts/django/docs/topics/db/multi-db.txt new file mode 100644 index 0000000..1a939b0 --- /dev/null +++ b/parts/django/docs/topics/db/multi-db.txt @@ -0,0 +1,574 @@ +================== +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 +with multiple databases, you'll need to take some additional steps. + +Defining your databases +======================= + +The first step to using more than one database with Django is to tell +Django about the database servers you'll be using. This is done using +the :setting:`DATABASES` setting. This setting maps database aliases, +which are a way to refer to a specific database throughout Django, to +a dictionary of settings for that specific connection. The settings in +the inner dictionaries are described fully in the :setting:`DATABASES` +documentation. + +Databases can have any alias you choose. However, the alias +``default`` has special significance. Django uses the database with +the alias of ``default`` when no other database has been selected. If +you don't have a ``default`` database, you need to be careful to +always specify the database that you want to use. + +The following is an example ``settings.py`` snippet defining two +databases -- a default PostgreSQL database and a MySQL database called +``users``: + +.. code-block:: python + + DATABASES = { + 'default': { + 'NAME': 'app_data', + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'USER': 'postgres_user', + 'PASSWORD': 's3krit' + }, + 'users': { + 'NAME': 'user_data', + 'ENGINE': 'django.db.backends.mysql', + 'USER': 'mysql_user', + 'PASSWORD': 'priv4te' + } + } + +If you attempt to access a database that you haven't defined in your +:setting:`DATABASES` setting, Django will raise a +``django.db.utils.ConnectionDoesNotExist`` exception. + +Synchronizing your databases +============================ + +The :djadmin:`syncdb` management command operates on one database at a +time. By default, it operates on the ``default`` database, but by +providing a :djadminopt:`--database` argument, you can tell syncdb to +synchronize a different database. So, to synchronize all models onto +all databases in our example, you would need to call:: + + $ ./manage.py syncdb + $ ./manage.py syncdb --database=users + +If you don't want every application to be synchronized onto a +particular database, you can define a :ref:`database +router<topics-db-multi-db-routing>` that implements a policy +constraining the availability of particular models. + +Alternatively, if you want fine-grained control of synchronization, +you can pipe all or part of the output of :djadmin:`sqlall` for a +particular application directly into your database prompt, like this:: + + $ ./manage.py sqlall sales | ./manage.py dbshell + +Using other management commands +------------------------------- + +The other ``django-admin.py`` commands that interact with the database +operate in the same way as :djadmin:`syncdb` -- they only ever operate +on one database at a time, using :djadminopt:`--database` to control +the database used. + +.. _topics-db-multi-db-routing: + +Automatic database routing +========================== + +The easiest way to use multiple databases is to set up a database +routing scheme. The default routing scheme ensures that objects remain +'sticky' to their original database (i.e., an object retrieved from +the ``foo`` database will be saved on the same database). The default +routing scheme ensures that if a database isn't specified, all queries +fall back to the ``default`` database. + +You don't have to do anything to activate the default routing scheme +-- it is provided 'out of the box' on every Django project. However, +if you want to implement more interesting database allocation +behaviors, you can define and install your own database routers. + +Database routers +---------------- + +A database Router is a class that provides up to four methods: + +.. method:: db_for_read(model, **hints) + + Suggest the database that should be used for read operations for + objects of type ``model``. + + If a database operation is able to provide any additional + information that might assist in selecting a database, it will be + provided in the ``hints`` dictionary. Details on valid hints are + provided :ref:`below <topics-db-multi-db-hints>`. + + Returns None if there is no suggestion. + +.. method:: db_for_write(model, **hints) + + Suggest the database that should be used for writes of objects of + type Model. + + If a database operation is able to provide any additional + information that might assist in selecting a database, it will be + provided in the ``hints`` dictionary. Details on valid hints are + provided :ref:`below <topics-db-multi-db-hints>`. + + Returns None if there is no suggestion. + +.. method:: allow_relation(obj1, obj2, **hints) + + Return True if a relation between obj1 and obj2 should be + allowed, False if the relation should be prevented, or None if + the router has no opinion. This is purely a validation operation, + used by foreign key and many to many operations to determine if a + relation should be allowed between two objects. + +.. method:: allow_syncdb(db, model) + + Determine if the ``model`` should be synchronized onto the + database with alias ``db``. Return True if the model should be + synchronized, False if it should not be synchronized, or None if + the router has no opinion. This method can be used to determine + the availability of a model on a given database. + +A router doesn't have to provide *all* these methods - it omit one or +more of them. If one of the methods is omitted, Django will skip that +router when performing the relevant check. + +.. _topics-db-multi-db-hints: + +Hints +~~~~~ + +The hints received by the database router can be used to decide which +database should receive a given request. + +At present, the only hint that will be provided is ``instance``, an +object instance that is related to the read or write operation that is +underway. This might be the instance that is being saved, or it might +be an instance that is being added in a many-to-many relation. In some +cases, no instance hint will be provided at all. The router checks for +the existence of an instance hint, and determine if that hint should be +used to alter routing behavior. + +Using routers +------------- + +Database routers are installed using the :setting:`DATABASE_ROUTERS` +setting. This setting defines a list of class names, each specifying a +router that should be used by the master router +(``django.db.router``). + +The master router is used by Django's database operations to allocate +database usage. Whenever a query needs to know which database to use, +it calls the master router, providing a model and a hint (if +available). Django then tries each router in turn until a database +suggestion can be found. If no suggestion can be found, it tries the +current ``_state.db`` of the hint instance. If a hint instance wasn't +provided, or the instance doesn't currently have database state, the +master router will allocate the ``default`` database. + +An example +---------- + +.. admonition:: Example purposes only! + + This example is intended as a demonstration of how the router + infrastructure can be used to alter database usage. It + intentionally ignores some complex issues in order to + demonstrate how routers are used. + + This example won't work if any of the models in ``myapp`` contain + relationships to models outside of the ``other`` database. + :ref:`Cross-database relationships <no_cross_database_relations>` + introduce referential integrity problems that Django can't + currently handle. + + The master/slave configuration described is also flawed -- it + doesn't provide any solution for handling replication lag (i.e., + query inconsistencies introduced because of the time taken for a + write to propagate to the slaves). It also doesn't consider the + interaction of transactions with the database utilization strategy. + +So - what does this mean in practice? Say you want ``myapp`` to +exist on the ``other`` database, and you want all other models in a +master/slave relationship between the databases ``master``, ``slave1`` and +``slave2``. To implement this, you would need 2 routers:: + + class MyAppRouter(object): + """A router to control all database operations on models in + the myapp application""" + + def db_for_read(self, model, **hints): + "Point all operations on myapp models to 'other'" + if model._meta.app_label == 'myapp': + return 'other' + return None + + def db_for_write(self, model, **hints): + "Point all operations on myapp models to 'other'" + if model._meta.app_label == 'myapp': + return 'other' + return None + + def allow_relation(self, obj1, obj2, **hints): + "Allow any relation if a model in myapp is involved" + if obj1._meta.app_label == 'myapp' or obj2._meta.app_label == 'myapp': + return True + return None + + def allow_syncdb(self, db, model): + "Make sure the myapp app only appears on the 'other' db" + if db == 'other': + return model._meta.app_label == 'myapp' + elif model._meta.app_label == 'myapp': + return False + return None + + class MasterSlaveRouter(object): + """A router that sets up a simple master/slave configuration""" + + def db_for_read(self, model, **hints): + "Point all read operations to a random slave" + return random.choice(['slave1','slave2']) + + def db_for_write(self, model, **hints): + "Point all write operations to the master" + return 'master' + + def allow_relation(self, obj1, obj2, **hints): + "Allow any relation between two objects in the db pool" + db_list = ('master','slave1','slave2') + if obj1._state.db in db_list and obj2._state.db in db_list: + return True + return None + + def allow_syncdb(self, db, model): + "Explicitly put all models on all databases." + return True + +Then, in your settings file, add the following (substituting ``path.to.`` with +the actual python path to the module where you define the routers):: + + DATABASE_ROUTERS = ['path.to.MyAppRouter', 'path.to.MasterSlaveRouter'] + +The order in which routers are processed is significant. Routers will +be queried in the order the are listed in the +:setting:`DATABASE_ROUTERS` setting . In this example, the +``MyAppRouter`` is processed before the ``MasterSlaveRouter``, and as a +result, decisions concerning the models in ``myapp`` are processed +before any other decision is made. If the :setting:`DATABASE_ROUTERS` +setting listed the two routers in the other order, +``MasterSlaveRouter.allow_syncdb()`` would be processed first. The +catch-all nature of the MasterSlaveRouter implementation would mean +that all models would be available on all databases. + +With this setup installed, lets run some Django code:: + + >>> # This retrieval will be performed on the 'credentials' database + >>> fred = User.objects.get(username='fred') + >>> fred.first_name = 'Frederick' + + >>> # This save will also be directed to 'credentials' + >>> fred.save() + + >>> # These retrieval will be randomly allocated to a slave database + >>> dna = Person.objects.get(name='Douglas Adams') + + >>> # A new object has no database allocation when created + >>> mh = Book(title='Mostly Harmless') + + >>> # This assignment will consult the router, and set mh onto + >>> # the same database as the author object + >>> mh.author = dna + + >>> # This save will force the 'mh' instance onto the master database... + >>> mh.save() + + >>> # ... but if we re-retrieve the object, it will come back on a slave + >>> mh = Book.objects.get(title='Mostly Harmless') + + +Manually selecting a database +============================= + +Django also provides an API that allows you to maintain complete control +over database usage in your code. A manually specified database allocation +will take priority over a database allocated by a router. + +Manually selecting a database for a ``QuerySet`` +------------------------------------------------ + +You can select the database for a ``QuerySet`` at any point in the +``QuerySet`` "chain." Just call ``using()`` on the ``QuerySet`` to get +another ``QuerySet`` that uses the specified database. + +``using()`` takes a single argument: the alias of the database on +which you want to run the query. For example:: + + >>> # This will run on the 'default' database. + >>> Author.objects.all() + + >>> # So will this. + >>> Author.objects.using('default').all() + + >>> # This will run on the 'other' database. + >>> Author.objects.using('other').all() + +Selecting a database for ``save()`` +----------------------------------- + +Use the ``using`` keyword to ``Model.save()`` to specify to which +database the data should be saved. + +For example, to save an object to the ``legacy_users`` database, you'd +use this:: + + >>> my_object.save(using='legacy_users') + +If you don't specify ``using``, the ``save()`` method will save into +the default database allocated by the routers. + +Moving an object from one database to another +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you've saved an instance to one database, it might be tempting to +use ``save(using=...)`` as a way to migrate the instance to a new +database. However, if you don't take appropriate steps, this could +have some unexpected consequences. + +Consider the following example:: + + >>> p = Person(name='Fred') + >>> p.save(using='first') # (statement 1) + >>> p.save(using='second') # (statement 2) + +In statement 1, a new ``Person`` object is saved to the ``first`` +database. At this time, ``p`` doesn't have a primary key, so Django +issues a SQL ``INSERT`` statement. This creates a primary key, and +Django assigns that primary key to ``p``. + +When the save occurs in statement 2, ``p`` already has a primary key +value, and Django will attempt to use that primary key on the new +database. If the primary key value isn't in use in the ``second`` +database, then you won't have any problems -- the object will be +copied to the new database. + +However, if the primary key of ``p`` is already in use on the +``second`` database, the existing object in the ``second`` database +will be overridden when ``p`` is saved. + +You can avoid this in two ways. First, you can clear the primary key +of the instance. If an object has no primary key, Django will treat it +as a new object, avoiding any loss of data on the ``second`` +database:: + + >>> p = Person(name='Fred') + >>> p.save(using='first') + >>> p.pk = None # Clear the primary key. + >>> p.save(using='second') # Write a completely new object. + +The second option is to use the ``force_insert`` option to ``save()`` +to ensure that Django does a SQL ``INSERT``:: + + >>> p = Person(name='Fred') + >>> p.save(using='first') + >>> p.save(using='second', force_insert=True) + +This will ensure that the person named ``Fred`` will have the same +primary key on both databases. If that primary key is already in use +when you try to save onto the ``second`` database, an error will be +raised. + +Selecting a database to delete from +----------------------------------- + +By default, a call to delete an existing object will be executed on +the same database that was used to retrieve the object in the first +place:: + + >>> u = User.objects.using('legacy_users').get(username='fred') + >>> u.delete() # will delete from the `legacy_users` database + +To specify the database from which a model will be deleted, pass a +``using`` keyword argument to the ``Model.delete()`` method. This +argument works just like the ``using`` keyword argument to ``save()``. + +For example, if you're migrating a user from the ``legacy_users`` +database to the ``new_users`` database, you might use these commands:: + + >>> user_obj.save(using='new_users') + >>> user_obj.delete(using='legacy_users') + +Using managers with multiple databases +-------------------------------------- + +Use the ``db_manager()`` method on managers to give managers access to +a non-default database. + +For example, say you have a custom manager method that touches the +database -- ``User.objects.create_user()``. Because ``create_user()`` +is a manager method, not a ``QuerySet`` method, you can't do +``User.objects.using('new_users').create_user()``. (The +``create_user()`` method is only available on ``User.objects``, the +manager, not on ``QuerySet`` objects derived from the manager.) The +solution is to use ``db_manager()``, like this:: + + User.objects.db_manager('new_users').create_user(...) + +``db_manager()`` returns a copy of the manager bound to the database you specify. + +Using ``get_query_set()`` with multiple databases +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you're overriding ``get_query_set()`` on your manager, be sure to +either call the method on the parent (using ``super()``) or do the +appropriate handling of the ``_db`` attribute on the manager (a string +containing the name of the database to use). + +For example, if you want to return a custom ``QuerySet`` class from +the ``get_query_set`` method, you could do this:: + + class MyManager(models.Manager): + def get_query_set(self): + qs = CustomQuerySet(self.model) + if self._db is not None: + qs = qs.using(self._db) + return qs + +Exposing multiple databases in Django's admin interface +======================================================= + +Django's admin doesn't have any explicit support for multiple +databases. If you want to provide an admin interface for a model on a +database other than that that specified by your router chain, you'll +need to write custom :class:`~django.contrib.admin.ModelAdmin` classes +that will direct the admin to use a specific database for content. + +``ModelAdmin`` objects have four methods that require customization for +multiple-database support:: + + class MultiDBModelAdmin(admin.ModelAdmin): + # A handy constant for the name of the alternate database. + using = 'other' + + def save_model(self, request, obj, form, change): + # Tell Django to save objects to the 'other' database. + obj.save(using=self.using) + + def queryset(self, request): + # Tell Django to look for objects on the 'other' database. + return super(MultiDBModelAdmin, self).queryset(request).using(self.using) + + def formfield_for_foreignkey(self, db_field, request=None, **kwargs): + # Tell Django to populate ForeignKey widgets using a query + # on the 'other' database. + return super(MultiDBModelAdmin, self).formfield_for_foreignkey(db_field, request=request, using=self.using, **kwargs) + + def formfield_for_manytomany(self, db_field, request=None, **kwargs): + # Tell Django to populate ManyToMany widgets using a query + # on the 'other' database. + return super(MultiDBModelAdmin, self).formfield_for_manytomany(db_field, request=request, using=self.using, **kwargs) + +The implementation provided here implements a multi-database strategy +where all objects of a given type are stored on a specific database +(e.g., all ``User`` objects are in the ``other`` database). If your +usage of multiple databases is more complex, your ``ModelAdmin`` will +need to reflect that strategy. + +Inlines can be handled in a similar fashion. They require three customized methods:: + + class MultiDBTabularInline(admin.TabularInline): + using = 'other' + + def queryset(self, request): + # Tell Django to look for inline objects on the 'other' database. + return super(MultiDBTabularInline, self).queryset(request).using(self.using) + + def formfield_for_foreignkey(self, db_field, request=None, **kwargs): + # Tell Django to populate ForeignKey widgets using a query + # on the 'other' database. + return super(MultiDBTabularInline, self).formfield_for_foreignkey(db_field, request=request, using=self.using, **kwargs) + + def formfield_for_manytomany(self, db_field, request=None, **kwargs): + # Tell Django to populate ManyToMany widgets using a query + # on the 'other' database. + return super(MultiDBTabularInline, self).formfield_for_manytomany(db_field, request=request, using=self.using, **kwargs) + +Once you've written your model admin definitions, they can be +registered with any ``Admin`` instance:: + + from django.contrib import admin + + # Specialize the multi-db admin objects for use with specific models. + class BookInline(MultiDBTabularInline): + model = Book + + class PublisherAdmin(MultiDBModelAdmin): + inlines = [BookInline] + + admin.site.register(Author, MultiDBModelAdmin) + admin.site.register(Publisher, PublisherAdmin) + + othersite = admin.Site('othersite') + othersite.register(Publisher, MultiDBModelAdmin) + +This example sets up two admin sites. On the first site, the +``Author`` and ``Publisher`` objects are exposed; ``Publisher`` +objects have an tabular inline showing books published by that +publisher. The second site exposes just publishers, without the +inlines. + +Using raw cursors with multiple databases +========================================= + +If you are using more than one database you can use +``django.db.connections`` to obtain the connection (and cursor) for a +specific database. ``django.db.connections`` is a dictionary-like +object that allows you to retrieve a specific connection using it's +alias:: + + from django.db import connections + cursor = connections['my_db_alias'].cursor() + +Limitations of multiple databases +================================= + +.. _no_cross_database_relations: + +Cross-database relations +------------------------ + +Django doesn't currently provide any support for foreign key or +many-to-many relationships spanning multiple databases. If you +have used a router to partition models to different databases, +any foreign key and many-to-many relationships defined by those +models must be internal to a single database. + +This is because of referential integrity. In order to maintain a +relationship between two objects, Django needs to know that the +primary key of the related object is valid. If the primary key is +stored on a separate database, it's not possible to easily evaluate +the validity of a primary key. + +If you're using Postgres, Oracle, or MySQL with InnoDB, this is +enforced at the database integrity level -- database level key +constraints prevent the creation of relations that can't be validated. + +However, if you're using SQLite or MySQL with MyISAM tables, there is +no enforced referential integrity; as a result, you may be able to +'fake' cross database foreign keys. However, this configuration is not +officially supported by Django. diff --git a/parts/django/docs/topics/db/optimization.txt b/parts/django/docs/topics/db/optimization.txt new file mode 100644 index 0000000..7d51052 --- /dev/null +++ b/parts/django/docs/topics/db/optimization.txt @@ -0,0 +1,260 @@ +============================ +Database access optimization +============================ + +Django's database layer provides various ways to help developers get the most +out of their databases. This document gathers together links to the relevant +documentation, and adds various tips, organized under a number of headings that +outline the steps to take when attempting to optimize your database usage. + +Profile first +============= + +As general programming practice, this goes without saying. Find out :ref:`what +queries you are doing and what they are costing you +<faq-see-raw-sql-queries>`. You may also want to use an external project like +django-debug-toolbar_, or a tool that monitors your database directly. + +Remember that you may be optimizing for speed or memory or both, depending on +your requirements. Sometimes optimizing for one will be detrimental to the +other, but sometimes they will help each other. Also, work that is done by the +database process might not have the same cost (to you) as the same amount of +work done in your Python process. It is up to you to decide what your +priorities are, where the balance must lie, and profile all of these as required +since this will depend on your application and server. + +With everything that follows, remember to profile after every change to ensure +that the change is a benefit, and a big enough benefit given the decrease in +readability of your code. **All** of the suggestions below come with the caveat +that in your circumstances the general principle might not apply, or might even +be reversed. + +.. _django-debug-toolbar: http://robhudson.github.com/django-debug-toolbar/ + +Use standard DB optimization techniques +======================================= + +...including: + +* Indexes. This is a number one priority, *after* you have determined from + profiling what indexes should be added. Use + :attr:`django.db.models.Field.db_index` to add these from Django. + +* Appropriate use of field types. + +We will assume you have done the obvious things above. The rest of this document +focuses on how to use Django in such a way that you are not doing unnecessary +work. This document also does not address other optimization techniques that +apply to all expensive operations, such as :doc:`general purpose caching +</topics/cache>`. + +Understand QuerySets +==================== + +Understanding :doc:`QuerySets </ref/models/querysets>` is vital to getting good +performance with simple code. In particular: + +Understand QuerySet evaluation +------------------------------ + +To avoid performance problems, it is important to understand: + +* that :ref:`QuerySets are lazy <querysets-are-lazy>`. + +* when :ref:`they are evaluated <when-querysets-are-evaluated>`. + +* how :ref:`the data is held in memory <caching-and-querysets>`. + +Understand cached attributes +---------------------------- + +As well as caching of the whole ``QuerySet``, there is caching of the result of +attributes on ORM objects. In general, attributes that are not callable will be +cached. For example, assuming the :ref:`example Weblog models +<queryset-model-example>`:: + + >>> entry = Entry.objects.get(id=1) + >>> entry.blog # Blog object is retrieved at this point + >>> entry.blog # cached version, no DB access + +But in general, callable attributes cause DB lookups every time:: + + >>> entry = Entry.objects.get(id=1) + >>> entry.authors.all() # query performed + >>> entry.authors.all() # query performed again + +Be careful when reading template code - the template system does not allow use +of parentheses, but will call callables automatically, hiding the above +distinction. + +Be careful with your own custom properties - it is up to you to implement +caching. + +Use the ``with`` template tag +----------------------------- + +To make use of the caching behaviour of ``QuerySet``, you may need to use the +:ttag:`with` template tag. + +Use ``iterator()`` +------------------ + +When you have a lot of objects, the caching behaviour of the ``QuerySet`` can +cause a large amount of memory to be used. In this case, +:meth:`~django.db.models.QuerySet.iterator()` may help. + +Do database work in the database rather than in Python +====================================================== + +For instance: + +* At the most basic level, use :ref:`filter and exclude <queryset-api>` to do + filtering in the database. + +* Use :ref:`F() object query expressions <query-expressions>` to do filtering + against other fields within the same model. + +* Use :doc:`annotate to do aggregation in the database </topics/db/aggregation>`. + +If these aren't enough to generate the SQL you need: + +Use ``QuerySet.extra()`` +------------------------ + +A less portable but more powerful method is +:meth:`~django.db.models.QuerySet.extra()`, which allows some SQL to be +explicitly added to the query. If that still isn't powerful enough: + +Use raw SQL +----------- + +Write your own :doc:`custom SQL to retrieve data or populate models +</topics/db/sql>`. Use ``django.db.connection.queries`` to find out what Django +is writing for you and start from there. + +Retrieve everything at once if you know you will need it +======================================================== + +Hitting the database multiple times for different parts of a single 'set' of +data that you will need all parts of is, in general, less efficient than +retrieving it all in one query. This is particularly important if you have a +query that is executed in a loop, and could therefore end up doing many database +queries, when only one was needed. So: + +Use ``QuerySet.select_related()`` +--------------------------------- + +Understand :ref:`QuerySet.select_related() <select-related>` thoroughly, and use it: + +* in view code, + +* and in :doc:`managers and default managers </topics/db/managers>` where + appropriate. Be aware when your manager is and is not used; sometimes this is + tricky so don't make assumptions. + +Don't retrieve things you don't need +==================================== + +Use ``QuerySet.values()`` and ``values_list()`` +----------------------------------------------- + +When you just want a ``dict`` or ``list`` of values, and don't need ORM model +objects, make appropriate usage of :meth:`~django.db.models.QuerySet.values()`. +These can be useful for replacing model objects in template code - as long as +the dicts you supply have the same attributes as those used in the template, +you are fine. + +Use ``QuerySet.defer()`` and ``only()`` +--------------------------------------- + +Use :meth:`~django.db.models.QuerySet.defer()` and +:meth:`~django.db.models.QuerySet.only()` if there are database columns you +know that you won't need (or won't need in most cases) to avoid loading +them. Note that if you *do* use them, the ORM will have to go and get them in a +separate query, making this a pessimization if you use it inappropriately. + +Use QuerySet.count() +-------------------- + +...if you only want the count, rather than doing ``len(queryset)``. + +Use QuerySet.exists() +--------------------- + +...if you only want to find out if at least one result exists, rather than ``if +queryset``. + +But: + +Don't overuse ``count()`` and ``exists()`` +------------------------------------------ + +If you are going to need other data from the QuerySet, just evaluate it. + +For example, assuming an Email class that has a ``body`` attribute and a +many-to-many relation to User, the following template code is optimal: + +.. code-block:: html+django + + {% if display_inbox %} + {% with user.emails.all as emails %} + {% if emails %} + <p>You have {{ emails|length }} email(s)</p> + {% for email in emails %} + <p>{{ email.body }}</p> + {% endfor %} + {% else %} + <p>No messages today.</p> + {% endif %} + {% endwith %} + {% endif %} + + +It is optimal because: + + 1. Since QuerySets are lazy, this does no database if 'display_inbox' is False. + + #. Use of ``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, + 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. + + #. The use of ``{{ emails|length }}`` calls ``QuerySet.__len__()``, filling + out the rest of the cache without doing another query. + + #. The ``for`` loop iterates over the already filled cache. + +In total, this code does either one or zero database queries. The only +deliberate optimization performed is the use of the ``with`` tag. Using +``QuerySet.exists()`` or ``QuerySet.count()`` at any point would cause +additional queries. + +Use ``QuerySet.update()`` and ``delete()`` +------------------------------------------ + +Rather than retrieve a load of objects, set some values, and save them +individual, use a bulk SQL UPDATE statement, via :ref:`QuerySet.update() +<topics-db-queries-update>`. Similarly, do :ref:`bulk deletes +<topics-db-queries-delete>` where possible. + +Note, however, that these bulk update methods cannot call the ``save()`` or +``delete()`` methods of individual instances, which means that any custom +behaviour you have added for these methods will not be executed, including +anything driven from the normal database object :doc:`signals </ref/signals>`. + +Use foreign key values directly +------------------------------- + +If you only need a foreign key value, use the foreign key value that is already on +the object you've got, rather than getting the whole related object and taking +its primary key. i.e. do:: + + entry.blog_id + +instead of:: + + entry.blog.id + diff --git a/parts/django/docs/topics/db/queries.txt b/parts/django/docs/topics/db/queries.txt new file mode 100644 index 0000000..923b1e4 --- /dev/null +++ b/parts/django/docs/topics/db/queries.txt @@ -0,0 +1,1110 @@ +============== +Making queries +============== + +.. currentmodule:: django.db.models + +Once you've created your :doc:`data models </topics/db/models>`, Django +automatically gives you a database-abstraction API that lets you create, +retrieve, update and delete objects. This document explains how to use this +API. Refer to the :doc:`data model reference </ref/models/index>` for full +details of all the various model lookup options. + +Throughout this guide (and in the reference), we'll refer to the following +models, which comprise a Weblog application: + +.. _queryset-model-example: + +.. code-block:: python + + class Blog(models.Model): + name = models.CharField(max_length=100) + tagline = models.TextField() + + def __unicode__(self): + return self.name + + class Author(models.Model): + name = models.CharField(max_length=50) + email = models.EmailField() + + def __unicode__(self): + return self.name + + class Entry(models.Model): + blog = models.ForeignKey(Blog) + headline = models.CharField(max_length=255) + body_text = models.TextField() + pub_date = models.DateTimeField() + authors = models.ManyToManyField(Author) + n_comments = models.IntegerField() + n_pingbacks = models.IntegerField() + rating = models.IntegerField() + + def __unicode__(self): + return self.headline + +Creating objects +================ + +To represent database-table data in Python objects, Django uses an intuitive +system: A model class represents a database table, and an instance of that +class represents a particular record in the database table. + +To create an object, instantiate it using keyword arguments to the model class, +then call ``save()`` to save it to the database. + +You import the model class from wherever it lives on the Python path, as you +may expect. (We point this out here because previous Django versions required +funky model importing.) + +Assuming models live in a file ``mysite/blog/models.py``, here's an example:: + + >>> from blog.models import Blog + >>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.') + >>> b.save() + +This performs an ``INSERT`` SQL statement behind the scenes. Django doesn't hit +the database until you explicitly call ``save()``. + +The ``save()`` method has no return value. + +.. seealso:: + + ``save()`` takes a number of advanced options not described here. + See the documentation for ``save()`` for complete details. + + To create an object and save it all in one step see the ```create()``` + method. + +Saving changes to objects +========================= + +To save changes to an object that's already in the database, use ``save()``. + +Given a ``Blog`` instance ``b5`` that has already been saved to the database, +this example changes its name and updates its record in the database:: + + >> b5.name = 'New name' + >> b5.save() + +This performs an ``UPDATE`` SQL statement behind the scenes. Django doesn't hit +the database until you explicitly call ``save()``. + +Saving ``ForeignKey`` and ``ManyToManyField`` fields +---------------------------------------------------- + +Updating a ``ForeignKey`` field works exactly the same way as saving a normal +field; simply assign an object of the right type to the field in question. +This example updates the ``blog`` attribute of an ``Entry`` instance ``entry``:: + + >>> from blog.models import Entry + >>> entry = Entry.objects.get(pk=1) + >>> cheese_blog = Blog.objects.get(name="Cheddar Talk") + >>> entry.blog = cheese_blog + >>> entry.save() + +Updating a ``ManyToManyField`` works a little differently; use the ``add()`` +method on the field to add a record to the relation. This example adds the +``Author`` instance ``joe`` to the ``entry`` object:: + + >>> from blog.models import Author + >>> joe = Author.objects.create(name="Joe") + >>> entry.authors.add(joe) + +Django will complain if you try to assign or add an object of the wrong type. + +Retrieving objects +================== + +To retrieve objects from your database, you construct a ``QuerySet`` via a +``Manager`` on your model class. + +A ``QuerySet`` represents a collection of objects from your database. It can +have zero, one or many *filters* -- criteria that narrow down the collection +based on given parameters. In SQL terms, a ``QuerySet`` equates to a ``SELECT`` +statement, and a filter is a limiting clause such as ``WHERE`` or ``LIMIT``. + +You get a ``QuerySet`` by using your model's ``Manager``. Each model has at +least one ``Manager``, and it's called ``objects`` by default. Access it +directly via the model class, like so:: + + >>> Blog.objects + <django.db.models.manager.Manager object at ...> + >>> b = Blog(name='Foo', tagline='Bar') + >>> b.objects + Traceback: + ... + AttributeError: "Manager isn't accessible via Blog instances." + +.. note:: + + ``Managers`` are accessible only via model classes, rather than from model + instances, to enforce a separation between "table-level" operations and + "record-level" operations. + +The ``Manager`` is the main source of ``QuerySets`` for a model. It acts as a +"root" ``QuerySet`` that describes all objects in the model's database table. +For example, ``Blog.objects`` is the initial ``QuerySet`` that contains all +``Blog`` objects in the database. + +Retrieving all objects +---------------------- + +The simplest way to retrieve objects from a table is to get all of them. +To do this, use the ``all()`` method on a ``Manager``:: + + >>> all_entries = Entry.objects.all() + +The ``all()`` method returns a ``QuerySet`` of all the objects in the database. + +(If ``Entry.objects`` is a ``QuerySet``, why can't we just do ``Entry.objects``? +That's because ``Entry.objects``, the root ``QuerySet``, is a special case +that cannot be evaluated. The ``all()`` method returns a ``QuerySet`` that +*can* be evaluated.) + + +Retrieving specific objects with filters +---------------------------------------- + +The root ``QuerySet`` provided by the ``Manager`` describes all objects in the +database table. Usually, though, you'll need to select only a subset of the +complete set of objects. + +To create such a subset, you refine the initial ``QuerySet``, adding filter +conditions. The two most common ways to refine a ``QuerySet`` are: + + ``filter(**kwargs)`` + Returns a new ``QuerySet`` containing objects that match the given + lookup parameters. + + ``exclude(**kwargs)`` + Returns a new ``QuerySet`` containing objects that do *not* match the + given lookup parameters. + +The lookup parameters (``**kwargs`` in the above function definitions) should +be in the format described in `Field lookups`_ below. + +For example, to get a ``QuerySet`` of blog entries from the year 2006, use +``filter()`` like so:: + + Entry.objects.filter(pub_date__year=2006) + +We don't have to add an ``all()`` -- ``Entry.objects.all().filter(...)``. That +would still work, but you only need ``all()`` when you want all objects from the +root ``QuerySet``. + +.. _chaining-filters: + +Chaining filters +~~~~~~~~~~~~~~~~ + +The result of refining a ``QuerySet`` is itself a ``QuerySet``, so it's +possible to chain refinements together. For example:: + + >>> Entry.objects.filter( + ... headline__startswith='What' + ... ).exclude( + ... pub_date__gte=datetime.now() + ... ).filter( + ... pub_date__gte=datetime(2005, 1, 1) + ... ) + +This takes the initial ``QuerySet`` of all entries in the database, adds a +filter, then an exclusion, then another filter. The final result is a +``QuerySet`` containing all entries with a headline that starts with "What", +that were published between January 1, 2005, and the current day. + +.. _filtered-querysets-are-unique: + +Filtered QuerySets are unique +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each time you refine a ``QuerySet``, you get a brand-new ``QuerySet`` that is +in no way bound to the previous ``QuerySet``. Each refinement creates a +separate and distinct ``QuerySet`` that can be stored, used and reused. + +Example:: + + >> q1 = Entry.objects.filter(headline__startswith="What") + >> q2 = q1.exclude(pub_date__gte=datetime.now()) + >> q3 = q1.filter(pub_date__gte=datetime.now()) + +These three ``QuerySets`` are separate. The first is a base ``QuerySet`` +containing all entries that contain a headline starting with "What". The second +is a subset of the first, with an additional criteria that excludes records +whose ``pub_date`` is greater than now. The third is a subset of the first, +with an additional criteria that selects only the records whose ``pub_date`` is +greater than now. The initial ``QuerySet`` (``q1``) is unaffected by the +refinement process. + +.. _querysets-are-lazy: + +QuerySets are lazy +~~~~~~~~~~~~~~~~~~ + +``QuerySets`` are lazy -- the act of creating a ``QuerySet`` doesn't involve any +database activity. You can stack filters together all day long, and Django won't +actually run the query until the ``QuerySet`` is *evaluated*. Take a look at +this example:: + + >>> q = Entry.objects.filter(headline__startswith="What") + >>> q = q.filter(pub_date__lte=datetime.now()) + >>> q = q.exclude(body_text__icontains="food") + >>> print q + +Though this looks like three database hits, in fact it hits the database only +once, at the last line (``print q``). In general, the results of a ``QuerySet`` +aren't fetched from the database until you "ask" for them. When you do, the +``QuerySet`` is *evaluated* by accessing the database. For more details on +exactly when evaluation takes place, see :ref:`when-querysets-are-evaluated`. + + +.. _retrieving-single-object-with-get: + +Retrieving a single object with get +----------------------------------- + +``.filter()`` will always give you a ``QuerySet``, even if only a single +object matches the query - in this case, it will be a ``QuerySet`` containing +a single element. + +If you know there is only one object that matches your query, you can use +the ``get()`` method on a `Manager` which returns the object directly:: + + >>> one_entry = Entry.objects.get(pk=1) + +You can use any query expression with ``get()``, just like with ``filter()`` - +again, see `Field lookups`_ below. + +Note that there is a difference between using ``.get()``, and using +``.filter()`` with a slice of ``[0]``. If there are no results that match the +query, ``.get()`` will raise a ``DoesNotExist`` exception. This exception is an +attribute of the model class that the query is being performed on - so in the +code above, if there is no ``Entry`` object with a primary key of 1, Django will +raise ``Entry.DoesNotExist``. + +Similarly, Django will complain if more than one item matches the ``get()`` +query. In this case, it will raise ``MultipleObjectsReturned``, which again is +an attribute of the model class itself. + + +Other QuerySet methods +---------------------- + +Most of the time you'll use ``all()``, ``get()``, ``filter()`` and ``exclude()`` +when you need to look up objects from the database. However, that's far from all +there is; see the :ref:`QuerySet API Reference <queryset-api>` for a complete +list of all the various ``QuerySet`` methods. + +.. _limiting-querysets: + +Limiting QuerySets +------------------ + +Use a subset of Python's array-slicing syntax to limit your ``QuerySet`` to a +certain number of results. This is the equivalent of SQL's ``LIMIT`` and +``OFFSET`` clauses. + +For example, this returns the first 5 objects (``LIMIT 5``):: + + >>> Entry.objects.all()[:5] + +This returns the sixth through tenth objects (``OFFSET 5 LIMIT 5``):: + + >>> Entry.objects.all()[5:10] + +Negative indexing (i.e. ``Entry.objects.all()[-1]``) is not supported. + +Generally, slicing a ``QuerySet`` returns a new ``QuerySet`` -- it doesn't +evaluate the query. An exception is if you use the "step" parameter of Python +slice syntax. For example, this would actually execute the query in order to +return a list of every *second* object of the first 10:: + + >>> Entry.objects.all()[:10:2] + +To retrieve a *single* object rather than a list +(e.g. ``SELECT foo FROM bar LIMIT 1``), use a simple index instead of a +slice. For example, this returns the first ``Entry`` in the database, after +ordering entries alphabetically by headline:: + + >>> Entry.objects.order_by('headline')[0] + +This is roughly equivalent to:: + + >>> Entry.objects.order_by('headline')[0:1].get() + +Note, however, that the first of these will raise ``IndexError`` while the +second will raise ``DoesNotExist`` if no objects match the given criteria. See +:meth:`~django.db.models.QuerySet.get` for more details. + +.. _field-lookups-intro: + +Field lookups +------------- + +Field lookups are how you specify the meat of an SQL ``WHERE`` clause. They're +specified as keyword arguments to the ``QuerySet`` methods ``filter()``, +``exclude()`` and ``get()``. + +Basic lookups keyword arguments take the form ``field__lookuptype=value``. +(That's a double-underscore). For example:: + + >>> Entry.objects.filter(pub_date__lte='2006-01-01') + +translates (roughly) into the following SQL:: + + SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01'; + +.. admonition:: How this is possible + + Python has the ability to define functions that accept arbitrary name-value + arguments whose names and values are evaluated at runtime. For more + information, see `Keyword Arguments`_ in the official Python tutorial. + + .. _`Keyword Arguments`: http://docs.python.org/tutorial/controlflow.html#keyword-arguments + +If you pass an invalid keyword argument, a lookup function will raise +``TypeError``. + +The database API supports about two dozen lookup types; a complete reference +can be found in the :ref:`field lookup reference <field-lookups>`. To give you a taste of what's available, here's some of the more common lookups +you'll probably use: + + :lookup:`exact` + An "exact" match. For example:: + + >>> Entry.objects.get(headline__exact="Man bites dog") + + Would generate SQL along these lines: + + .. code-block:: sql + + SELECT ... WHERE headline = 'Man bites dog'; + + If you don't provide a lookup type -- that is, if your keyword argument + doesn't contain a double underscore -- the lookup type is assumed to be + ``exact``. + + For example, the following two statements are equivalent:: + + >>> Blog.objects.get(id__exact=14) # Explicit form + >>> Blog.objects.get(id=14) # __exact is implied + + This is for convenience, because ``exact`` lookups are the common case. + + :lookup:`iexact` + A case-insensitive match. So, the query:: + + >>> Blog.objects.get(name__iexact="beatles blog") + + Would match a ``Blog`` titled "Beatles Blog", "beatles blog", or even + "BeAtlES blOG". + + :lookup:`contains` + Case-sensitive containment test. For example:: + + Entry.objects.get(headline__contains='Lennon') + + Roughly translates to this SQL: + + .. code-block:: sql + + SELECT ... WHERE headline LIKE '%Lennon%'; + + Note this will match the headline ``'Today Lennon honored'`` but not + ``'today lennon honored'``. + + There's also a case-insensitive version, :lookup:`icontains`. + + :lookup:`startswith`, :lookup:`endswith` + Starts-with and ends-with search, respectively. There are also + case-insensitive versions called :lookup:`istartswith` and + :lookup:`iendswith`. + +Again, this only scratches the surface. A complete reference can be found in the +:ref:`field lookup reference <field-lookups>`. + +Lookups that span relationships +------------------------------- + +Django offers a powerful and intuitive way to "follow" relationships in +lookups, taking care of the SQL ``JOIN``\s for you automatically, behind the +scenes. To span a relationship, just use the field name of related fields +across models, separated by double underscores, until you get to the field you +want. + +This example retrieves all ``Entry`` objects with a ``Blog`` whose ``name`` +is ``'Beatles Blog'``:: + + >>> Entry.objects.filter(blog__name__exact='Beatles Blog') + +This spanning can be as deep as you'd like. + +It works backwards, too. To refer to a "reverse" relationship, just use the +lowercase name of the model. + +This example retrieves all ``Blog`` objects which have at least one ``Entry`` +whose ``headline`` contains ``'Lennon'``:: + + >>> Blog.objects.filter(entry__headline__contains='Lennon') + +If you are filtering across multiple relationships and one of the intermediate +models doesn't have a value that meets the filter condition, Django will treat +it as if there is an empty (all values are ``NULL``), but valid, object there. +All this means is that no error will be raised. For example, in this filter:: + + Blog.objects.filter(entry__authors__name='Lennon') + +(if there was a related ``Author`` model), if there was no ``author`` +associated with an entry, it would be treated as if there was also no ``name`` +attached, rather than raising an error because of the missing ``author``. +Usually this is exactly what you want to have happen. The only case where it +might be confusing is if you are using ``isnull``. Thus:: + + Blog.objects.filter(entry__authors__name__isnull=True) + +will return ``Blog`` objects that have an empty ``name`` on the ``author`` and +also those which have an empty ``author`` on the ``entry``. If you don't want +those latter objects, you could write:: + + Blog.objects.filter(entry__authors__isnull=False, + entry__authors__name__isnull=True) + +Spanning multi-valued relationships +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.0 + +When you are filtering an object based on a ``ManyToManyField`` or a reverse +``ForeignKey``, there are two different sorts of filter you may be +interested in. Consider the ``Blog``/``Entry`` relationship (``Blog`` to +``Entry`` is a one-to-many relation). We might be interested in finding blogs +that have an entry which has both *"Lennon"* in the headline and was published +in 2008. Or we might want to find blogs that have an entry with *"Lennon"* in +the headline as well as an entry that was published in 2008. Since there are +multiple entries associated with a single ``Blog``, both of these queries are +possible and make sense in some situations. + +The same type of situation arises with a ``ManyToManyField``. For example, if +an ``Entry`` has a ``ManyToManyField`` called ``tags``, we might want to find +entries linked to tags called *"music"* and *"bands"* or we might want an +entry that contains a tag with a name of *"music"* and a status of *"public"*. + +To handle both of these situations, Django has a consistent way of processing +``filter()`` and ``exclude()`` calls. Everything inside a single ``filter()`` +call is applied simultaneously to filter out items matching all those +requirements. Successive ``filter()`` calls further restrict the set of +objects, but for multi-valued relations, they apply to any object linked to +the primary model, not necessarily those objects that were selected by an +earlier ``filter()`` call. + +That may sound a bit confusing, so hopefully an example will clarify. To +select all blogs that contain entries with both *"Lennon"* in the headline +and that were published in 2008 (the same entry satisfying both conditions), +we would write:: + + Blog.objects.filter(entry__headline__contains='Lennon', + entry__pub_date__year=2008) + +To select all blogs that contain an entry with *"Lennon"* in the headline +**as well as** an entry that was published in 2008, we would write:: + + Blog.objects.filter(entry__headline__contains='Lennon').filter( + entry__pub_date__year=2008) + +In this second example, the first filter restricted the queryset to all those +blogs linked to that particular type of entry. The second filter restricted +the set of blogs *further* to those that are also linked to the second type of +entry. The entries select by the second filter may or may not be the same as +the entries in the first filter. We are filtering the ``Blog`` items with each +filter statement, not the ``Entry`` items. + +All of this behavior also applies to ``exclude()``: all the conditions in a +single ``exclude()`` statement apply to a single instance (if those conditions +are talking about the same multi-valued relation). Conditions in subsequent +``filter()`` or ``exclude()`` calls that refer to the same relation may end up +filtering on different linked objects. + +.. _query-expressions: + +Filters can reference fields on the model +----------------------------------------- + +.. versionadded:: 1.1 + +In the examples given so far, we have constructed filters that compare +the value of a model field with a constant. But what if you want to compare +the value of a model field with another field on the same model? + +Django provides the ``F()`` object to allow such comparisons. Instances +of ``F()`` act as a reference to a model field within a query. These +references can then be used in query filters to compare the values of two +different fields on the same model instance. + +For example, to find a list of all blog entries that have had more comments +than pingbacks, we construct an ``F()`` object to reference the comment count, +and use that ``F()`` object in the query:: + + >>> from django.db.models import F + >>> Entry.objects.filter(n_comments__gt=F('n_pingbacks')) + +Django supports the use of addition, subtraction, multiplication, +division and modulo arithmetic with ``F()`` objects, both with constants +and with other ``F()`` objects. To find all the blog entries with more than +*twice* as many comments as pingbacks, we modify the query:: + + >>> Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2) + +To find all the entries where the rating of the entry is less than the +sum of the pingback count and comment count, we would issue the +query:: + + >>> Entry.objects.filter(rating__lt=F('n_comments') + F('n_pingbacks')) + +You can also use the double underscore notation to span relationships in +an ``F()`` object. An ``F()`` object with a double underscore will introduce +any joins needed to access the related object. For example, to retrieve all +the entries where the author's name is the same as the blog name, we could +issue the query: + + >>> Entry.objects.filter(authors__name=F('blog__name')) + +The pk lookup shortcut +---------------------- + +For convenience, Django provides a ``pk`` lookup shortcut, which stands for +"primary key". + +In the example ``Blog`` model, the primary key is the ``id`` field, so these +three statements are equivalent:: + + >>> Blog.objects.get(id__exact=14) # Explicit form + >>> Blog.objects.get(id=14) # __exact is implied + >>> Blog.objects.get(pk=14) # pk implies id__exact + +The use of ``pk`` isn't limited to ``__exact`` queries -- any query term +can be combined with ``pk`` to perform a query on the primary key of a model:: + + # Get blogs entries with id 1, 4 and 7 + >>> Blog.objects.filter(pk__in=[1,4,7]) + + # Get all blog entries with id > 14 + >>> Blog.objects.filter(pk__gt=14) + +``pk`` lookups also work across joins. For example, these three statements are +equivalent:: + + >>> Entry.objects.filter(blog__id__exact=3) # Explicit form + >>> Entry.objects.filter(blog__id=3) # __exact is implied + >>> Entry.objects.filter(blog__pk=3) # __pk implies __id__exact + +Escaping percent signs and underscores in LIKE statements +--------------------------------------------------------- + +The field lookups that equate to ``LIKE`` SQL statements (``iexact``, +``contains``, ``icontains``, ``startswith``, ``istartswith``, ``endswith`` +and ``iendswith``) will automatically escape the two special characters used in +``LIKE`` statements -- the percent sign and the underscore. (In a ``LIKE`` +statement, the percent sign signifies a multiple-character wildcard and the +underscore signifies a single-character wildcard.) + +This means things should work intuitively, so the abstraction doesn't leak. +For example, to retrieve all the entries that contain a percent sign, just use +the percent sign as any other character:: + + >>> Entry.objects.filter(headline__contains='%') + +Django takes care of the quoting for you; the resulting SQL will look something +like this: + +.. code-block:: sql + + SELECT ... WHERE headline LIKE '%\%%'; + +Same goes for underscores. Both percentage signs and underscores are handled +for you transparently. + +.. _caching-and-querysets: + +Caching and QuerySets +--------------------- + +Each ``QuerySet`` contains a cache, to minimize database access. It's important +to understand how it works, in order to write the most efficient code. + +In a newly created ``QuerySet``, the cache is empty. The first time a +``QuerySet`` is evaluated -- and, hence, a database query happens -- Django +saves the query results in the ``QuerySet``'s cache and returns the results +that have been explicitly requested (e.g., the next element, if the +``QuerySet`` is being iterated over). Subsequent evaluations of the +``QuerySet`` reuse the cached results. + +Keep this caching behavior in mind, because it may bite you if you don't use +your ``QuerySet``\s correctly. For example, the following will create two +``QuerySet``\s, evaluate them, and throw them away:: + + >>> print [e.headline for e in Entry.objects.all()] + >>> print [e.pub_date for e in Entry.objects.all()] + +That means the same database query will be executed twice, effectively doubling +your database load. Also, there's a possibility the two lists may not include +the same database records, because an ``Entry`` may have been added or deleted +in the split second between the two requests. + +To avoid this problem, simply save the ``QuerySet`` and reuse it:: + + >>> queryset = Entry.objects.all() + >>> print [p.headline for p in queryset] # Evaluate the query set. + >>> print [p.pub_date for p in queryset] # Re-use the cache from the evaluation. + +.. _complex-lookups-with-q: + +Complex lookups with Q objects +============================== + +Keyword argument queries -- in ``filter()``, etc. -- are "AND"ed together. If +you need to execute more complex queries (for example, queries with ``OR`` +statements), you can use ``Q`` objects. + +A ``Q`` object (``django.db.models.Q``) is an object used to encapsulate a +collection of keyword arguments. These keyword arguments are specified as in +"Field lookups" above. + +For example, this ``Q`` object encapsulates a single ``LIKE`` query:: + + Q(question__startswith='What') + +``Q`` objects can be combined using the ``&`` and ``|`` operators. When an +operator is used on two ``Q`` objects, it yields a new ``Q`` object. + +For example, this statement yields a single ``Q`` object that represents the +"OR" of two ``"question__startswith"`` queries:: + + Q(question__startswith='Who') | Q(question__startswith='What') + +This is equivalent to the following SQL ``WHERE`` clause:: + + WHERE question LIKE 'Who%' OR question LIKE 'What%' + +You can compose statements of arbitrary complexity by combining ``Q`` objects +with the ``&`` and ``|`` operators and use parenthetical grouping. Also, ``Q`` +objects can be negated using the ``~`` operator, allowing for combined lookups +that combine both a normal query and a negated (``NOT``) query:: + + Q(question__startswith='Who') | ~Q(pub_date__year=2005) + +Each lookup function that takes keyword-arguments (e.g. ``filter()``, +``exclude()``, ``get()``) can also be passed one or more ``Q`` objects as +positional (not-named) arguments. If you provide multiple ``Q`` object +arguments to a lookup function, the arguments will be "AND"ed together. For +example:: + + Poll.objects.get( + Q(question__startswith='Who'), + Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)) + ) + +... roughly translates into the SQL:: + + SELECT * from polls WHERE question LIKE 'Who%' + AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06') + +Lookup functions can mix the use of ``Q`` objects and keyword arguments. All +arguments provided to a lookup function (be they keyword arguments or ``Q`` +objects) are "AND"ed together. However, if a ``Q`` object is provided, it must +precede the definition of any keyword arguments. For example:: + + Poll.objects.get( + Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)), + question__startswith='Who') + +... would be a valid query, equivalent to the previous example; but:: + + # INVALID QUERY + Poll.objects.get( + question__startswith='Who', + Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))) + +... would not be valid. + +.. seealso:: + + The `OR lookups examples`_ in the Django unit tests show some possible uses + of ``Q``. + + .. _OR lookups examples: http://code.djangoproject.com/browser/django/trunk/tests/modeltests/or_lookups/tests.py + +Comparing objects +================= + +To compare two model instances, just use the standard Python comparison operator, +the double equals sign: ``==``. Behind the scenes, that compares the primary +key values of two models. + +Using the ``Entry`` example above, the following two statements are equivalent:: + + >>> some_entry == other_entry + >>> some_entry.id == other_entry.id + +If a model's primary key isn't called ``id``, no problem. Comparisons will +always use the primary key, whatever it's called. For example, if a model's +primary key field is called ``name``, these two statements are equivalent:: + + >>> some_obj == other_obj + >>> some_obj.name == other_obj.name + +.. _topics-db-queries-delete: + +Deleting objects +================ + +The delete method, conveniently, is named ``delete()``. This method immediately +deletes the object and has no return value. Example:: + + e.delete() + +You can also delete objects in bulk. Every ``QuerySet`` has a ``delete()`` +method, which deletes all members of that ``QuerySet``. + +For example, this deletes all ``Entry`` objects with a ``pub_date`` year of +2005:: + + Entry.objects.filter(pub_date__year=2005).delete() + +Keep in mind that this will, whenever possible, be executed purely in +SQL, and so the ``delete()`` methods of individual object instances +will not necessarily be called during the process. If you've provided +a custom ``delete()`` method on a model class and want to ensure that +it is called, you will need to "manually" delete instances of that +model (e.g., by iterating over a ``QuerySet`` and calling ``delete()`` +on each object individually) rather than using the bulk ``delete()`` +method of a ``QuerySet``. + +When Django deletes an object, it emulates the behavior of the SQL +constraint ``ON DELETE CASCADE`` -- in other words, any objects which +had foreign keys pointing at the object to be deleted will be deleted +along with it. For example:: + + b = Blog.objects.get(pk=1) + # This will delete the Blog and all of its Entry objects. + b.delete() + +Note that ``delete()`` is the only ``QuerySet`` method that is not exposed on a +``Manager`` itself. This is a safety mechanism to prevent you from accidentally +requesting ``Entry.objects.delete()``, and deleting *all* the entries. If you +*do* want to delete all the objects, then you have to explicitly request a +complete query set:: + + Entry.objects.all().delete() + +.. _topics-db-queries-update: + +Updating multiple objects at once +================================= + +.. versionadded:: 1.0 + +Sometimes you want to set a field to a particular value for all the objects in +a ``QuerySet``. You can do this with the ``update()`` method. For example:: + + # Update all the headlines with pub_date in 2007. + Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same') + +You can only set non-relation fields and ``ForeignKey`` fields using this +method. To update a non-relation field, provide the new value as a constant. +To update ``ForeignKey`` fields, set the new value to be the new model +instance you want to point to. For example:: + + >>> b = Blog.objects.get(pk=1) + + # Change every Entry so that it belongs to this Blog. + >>> Entry.objects.all().update(blog=b) + +The ``update()`` method is applied instantly and returns the number of rows +affected by the query. The only restriction on the ``QuerySet`` that is +updated is that it can only access one database table, the model's main +table. You can filter based on related fields, but you can only update columns +in the model's main table. Example:: + + >>> b = Blog.objects.get(pk=1) + + # Update all the headlines belonging to this Blog. + >>> Entry.objects.select_related().filter(blog=b).update(headline='Everything is the same') + +Be aware that the ``update()`` method is converted directly to an SQL +statement. It is a bulk operation for direct updates. It doesn't run any +``save()`` methods on your models, or emit the ``pre_save`` or ``post_save`` +signals (which are a consequence of calling ``save()``). If you want to save +every item in a ``QuerySet`` and make sure that the ``save()`` method is +called on each instance, you don't need any special function to handle that. +Just loop over them and call ``save()``:: + + for item in my_queryset: + item.save() + +.. versionadded:: 1.1 + +Calls to update can also use :ref:`F() objects <query-expressions>` to update +one field based on the value of another field in the model. This is especially +useful for incrementing counters based upon their current value. For example, to +increment the pingback count for every entry in the blog:: + + >>> Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1) + +However, unlike ``F()`` objects in filter and exclude clauses, you can't +introduce joins when you use ``F()`` objects in an update -- you can only +reference fields local to the model being updated. If you attempt to introduce +a join with an ``F()`` object, a ``FieldError`` will be raised:: + + # THIS WILL RAISE A FieldError + >>> Entry.objects.update(headline=F('blog__name')) + +Related objects +=============== + +When you define a relationship in a model (i.e., a ``ForeignKey``, +``OneToOneField``, or ``ManyToManyField``), instances of that model will have +a convenient API to access the related object(s). + +Using the models at the top of this page, for example, an ``Entry`` object ``e`` +can get its associated ``Blog`` object by accessing the ``blog`` attribute: +``e.blog``. + +(Behind the scenes, this functionality is implemented by Python descriptors_. +This shouldn't really matter to you, but we point it out here for the curious.) + +Django also creates API accessors for the "other" side of the relationship -- +the link from the related model to the model that defines the relationship. +For example, a ``Blog`` object ``b`` has access to a list of all related +``Entry`` objects via the ``entry_set`` attribute: ``b.entry_set.all()``. + +All examples in this section use the sample ``Blog``, ``Author`` and ``Entry`` +models defined at the top of this page. + +.. _descriptors: http://users.rcn.com/python/download/Descriptor.htm + +One-to-many relationships +------------------------- + +Forward +~~~~~~~ + +If a model has a ``ForeignKey``, instances of that model will have access to +the related (foreign) object via a simple attribute of the model. + +Example:: + + >>> e = Entry.objects.get(id=2) + >>> e.blog # Returns the related Blog object. + +You can get and set via a foreign-key attribute. As you may expect, changes to +the foreign key aren't saved to the database until you call ``save()``. +Example:: + + >>> e = Entry.objects.get(id=2) + >>> e.blog = some_blog + >>> e.save() + +If a ``ForeignKey`` field has ``null=True`` set (i.e., it allows ``NULL`` +values), you can assign ``None`` to it. Example:: + + >>> e = Entry.objects.get(id=2) + >>> e.blog = None + >>> e.save() # "UPDATE blog_entry SET blog_id = NULL ...;" + +Forward access to one-to-many relationships is cached the first time the +related object is accessed. Subsequent accesses to the foreign key on the same +object instance are cached. Example:: + + >>> e = Entry.objects.get(id=2) + >>> print e.blog # Hits the database to retrieve the associated Blog. + >>> print e.blog # Doesn't hit the database; uses cached version. + +Note that the ``select_related()`` ``QuerySet`` method recursively prepopulates +the cache of all one-to-many relationships ahead of time. Example:: + + >>> e = Entry.objects.select_related().get(id=2) + >>> print e.blog # Doesn't hit the database; uses cached version. + >>> print e.blog # Doesn't hit the database; uses cached version. + +.. _backwards-related-objects: + +Following relationships "backward" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a model has a ``ForeignKey``, instances of the foreign-key model will have +access to a ``Manager`` that returns all instances of the first model. By +default, this ``Manager`` is named ``FOO_set``, where ``FOO`` is the source +model name, lowercased. This ``Manager`` returns ``QuerySets``, which can be +filtered and manipulated as described in the "Retrieving objects" section +above. + +Example:: + + >>> b = Blog.objects.get(id=1) + >>> b.entry_set.all() # Returns all Entry objects related to Blog. + + # b.entry_set is a Manager that returns QuerySets. + >>> b.entry_set.filter(headline__contains='Lennon') + >>> b.entry_set.count() + +You can override the ``FOO_set`` name by setting the ``related_name`` +parameter in the ``ForeignKey()`` definition. For example, if the ``Entry`` +model was altered to ``blog = ForeignKey(Blog, related_name='entries')``, the +above example code would look like this:: + + >>> b = Blog.objects.get(id=1) + >>> b.entries.all() # Returns all Entry objects related to Blog. + + # b.entries is a Manager that returns QuerySets. + >>> b.entries.filter(headline__contains='Lennon') + >>> b.entries.count() + +You cannot access a reverse ``ForeignKey`` ``Manager`` from the class; it must +be accessed from an instance:: + + >>> Blog.entry_set + Traceback: + ... + AttributeError: "Manager must be accessed via instance". + +In addition to the ``QuerySet`` methods defined in "Retrieving objects" above, +the ``ForeignKey`` ``Manager`` has additional methods used to handle the set of +related objects. A synopsis of each is below, and complete details can be found +in the :doc:`related objects reference </ref/models/relations>`. + +``add(obj1, obj2, ...)`` + Adds the specified model objects to the related object set. + +``create(**kwargs)`` + Creates a new object, saves it and puts it in the related object set. + Returns the newly created object. + +``remove(obj1, obj2, ...)`` + Removes the specified model objects from the related object set. + +``clear()`` + Removes all objects from the related object set. + +To assign the members of a related set in one fell swoop, just assign to it +from any iterable object. The iterable can contain object instances, or just +a list of primary key values. For example:: + + b = Blog.objects.get(id=1) + b.entry_set = [e1, e2] + +In this example, ``e1`` and ``e2`` can be full Entry instances, or integer +primary key values. + +If the ``clear()`` method is available, any pre-existing objects will be +removed from the ``entry_set`` before all objects in the iterable (in this +case, a list) are added to the set. If the ``clear()`` method is *not* +available, all objects in the iterable will be added without removing any +existing elements. + +Each "reverse" operation described in this section has an immediate effect on +the database. Every addition, creation and deletion is immediately and +automatically saved to the database. + +Many-to-many relationships +-------------------------- + +Both ends of a many-to-many relationship get automatic API access to the other +end. The API works just as a "backward" one-to-many relationship, above. + +The only difference is in the attribute naming: The model that defines the +``ManyToManyField`` uses the attribute name of that field itself, whereas the +"reverse" model uses the lowercased model name of the original model, plus +``'_set'`` (just like reverse one-to-many relationships). + +An example makes this easier to understand:: + + e = Entry.objects.get(id=3) + e.authors.all() # Returns all Author objects for this Entry. + e.authors.count() + e.authors.filter(name__contains='John') + + a = Author.objects.get(id=5) + a.entry_set.all() # Returns all Entry objects for this Author. + +Like ``ForeignKey``, ``ManyToManyField`` can specify ``related_name``. In the +above example, if the ``ManyToManyField`` in ``Entry`` had specified +``related_name='entries'``, then each ``Author`` instance would have an +``entries`` attribute instead of ``entry_set``. + +One-to-one relationships +------------------------ + +One-to-one relationships are very similar to many-to-one relationships. If you +define a :class:`~django.db.models.OneToOneField` on your model, instances of +that model will have access to the related object via a simple attribute of the +model. + +For example:: + + class EntryDetail(models.Model): + entry = models.OneToOneField(Entry) + details = models.TextField() + + ed = EntryDetail.objects.get(id=2) + ed.entry # Returns the related Entry object. + +The difference comes in "reverse" queries. The related model in a one-to-one +relationship also has access to a :class:`~django.db.models.Manager` object, but +that :class:`~django.db.models.Manager` represents a single object, rather than +a collection of objects:: + + e = Entry.objects.get(id=2) + e.entrydetail # returns the related EntryDetail object + +If no object has been assigned to this relationship, Django will raise +a ``DoesNotExist`` exception. + +Instances can be assigned to the reverse relationship in the same way as +you would assign the forward relationship:: + + e.entrydetail = ed + +How are the backward relationships possible? +-------------------------------------------- + +Other object-relational mappers require you to define relationships on both +sides. The Django developers believe this is a violation of the DRY (Don't +Repeat Yourself) principle, so Django only requires you to define the +relationship on one end. + +But how is this possible, given that a model class doesn't know which other +model classes are related to it until those other model classes are loaded? + +The answer lies in the :setting:`INSTALLED_APPS` setting. The first time any model is +loaded, Django iterates over every model in :setting:`INSTALLED_APPS` and creates the +backward relationships in memory as needed. Essentially, one of the functions +of :setting:`INSTALLED_APPS` is to tell Django the entire model domain. + +Queries over related objects +---------------------------- + +Queries involving related objects follow the same rules as queries involving +normal value fields. When specifying the value for a query to match, you may +use either an object instance itself, or the primary key value for the object. + +For example, if you have a Blog object ``b`` with ``id=5``, the following +three queries would be identical:: + + Entry.objects.filter(blog=b) # Query using object instance + Entry.objects.filter(blog=b.id) # Query using id from instance + Entry.objects.filter(blog=5) # Query using id directly + +Falling back to raw SQL +======================= + +If you find yourself needing to write an SQL query that is too complex for +Django's database-mapper to handle, you can fall back on writing SQL by hand. +Django has a couple of options for writing raw SQL queries; see +:doc:`/topics/db/sql`. + +Finally, it's important to note that the Django database layer is merely an +interface to your database. You can access your database via other tools, +programming languages or database frameworks; there's nothing Django-specific +about your database. diff --git a/parts/django/docs/topics/db/sql.txt b/parts/django/docs/topics/db/sql.txt new file mode 100644 index 0000000..cac9a72 --- /dev/null +++ b/parts/django/docs/topics/db/sql.txt @@ -0,0 +1,279 @@ +========================== +Performing raw SQL queries +========================== + +.. currentmodule:: django.db.models + +When the :doc:`model query APIs </topics/db/queries>` don't go far enough, you +can fall back to writing raw SQL. Django gives you two ways of performing raw +SQL queries: you can use :meth:`Manager.raw()` to `perform raw queries and +return model instances`__, or you can avoid the model layer entirely and +`execute custom SQL directly`__. + +__ `performing raw queries`_ +__ `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: + +.. method:: Manager.raw(raw_query, params=None, translations=None) + +This method method takes a raw SQL query, executes it, and returns a +:class:`~django.db.models.query.RawQuerySet` instance. This +:class:`~django.db.models.query.RawQuerySet` instance can be iterated +over just like an normal QuerySet to provide object instances. + +This is best illustrated with an example. Suppose you've got the following model:: + + class Person(models.Model): + first_name = models.CharField(...) + last_name = models.CharField(...) + birth_date = models.DateField(...) + +You could then execute custom SQL like so:: + + >>> for p in Person.objects.raw('SELECT * FROM myapp_person'): + ... print p + John Smith + Jane Jones + +.. admonition:: Model table names + + Where'd the name of the ``Person`` table come from in that example? + + By default, Django figures out a database table name by joining the + model's "app label" -- the name you used in ``manage.py startapp`` -- to + the model's class name, with an underscore between them. In the example + we've assumed that the ``Person`` model lives in an app named ``myapp``, + so its table would be ``myapp_person``. + + For more details check out the documentation for the + :attr:`~Options.db_table` option, which also lets you manually set the + database table name. + +Of course, this example isn't very exciting -- it's exactly the same as +running ``Person.objects.all()``. However, ``raw()`` has a bunch of other +options that make it very powerful. + +Mapping query fields to model fields +------------------------------------ + +``raw()`` automatically maps fields in the query to fields on the model. + +The order of fields in your query doesn't matter. In other words, both +of the following queries work identically:: + + >>> Person.objects.raw('SELECT id, first_name, last_name, birth_date FROM myapp_person') + ... + >>> Person.objects.raw('SELECT last_name, birth_date, first_name, id FROM myapp_person') + ... + +Matching is done by name. This means that you can use SQL's ``AS`` clauses to +map fields in the query to model fields. So if you had some other table that +had ``Person`` data in it, you could easily map it into ``Person`` instances:: + + >>> Person.objects.raw('''SELECT first AS first_name, + ... last AS last_name, + ... bd AS birth_date, + ... pk as id, + ... FROM some_other_table''') + +As long as the names match, the model instances will be created correctly. + +Alternatively, you can map fields in the query to model fields using the +``translations`` argument to ``raw()``. This is a dictionary mapping names of +fields in the query to names of fields on the model. For example, the above +query could also be written:: + + >>> name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'} + >>> Person.objects.raw('SELECT * FROM some_other_table', translations=name_map) + +Index lookups +------------- + +``raw()`` supports indexing, so if you need only the first result you can +write:: + + >>> first_person = Person.objects.raw('SELECT * from myapp_person')[0] + +However, the indexing and slicing are not performed at the database level. If +you have a big amount of ``Person`` objects in your database, it is more +efficient to limit the query at the SQL level:: + + >>> first_person = Person.objects.raw('SELECT * from myapp_person LIMIT 1')[0] + +Deferring model fields +---------------------- + +Fields may also be left out:: + + >>> people = Person.objects.raw('SELECT id, first_name FROM myapp_person') + +The ``Person`` objects returned by this query will be deferred model instances +(see :meth:`~django.db.models.QuerySet.defer()`). This means that the fields +that are omitted from the query will be loaded on demand. For example:: + + >>> for p in Person.objects.raw('SELECT id, first_name FROM myapp_person'): + ... print p.first_name, # This will be retrieved by the original query + ... print p.last_name # This will be retrieved on demand + ... + John Smith + Jane Jones + +From outward appearances, this looks like the query has retrieved both +the first name and last name. However, this example actually issued 3 +queries. Only the first names were retrieved by the raw() query -- the +last names were both retrieved on demand when they were printed. + +There is only one field that you can't leave out - the primary key +field. Django uses the primary key to identify model instances, so it +must always be included in a raw query. An ``InvalidQuery`` exception +will be raised if you forget to include the primary key. + +Adding annotations +------------------ + +You can also execute queries containing fields that aren't defined on the +model. For example, we could use `PostgreSQL's age() function`__ to get a list +of people with their ages calculated by the database:: + + >>> people = Person.objects.raw('SELECT *, age(birth_date) AS age FROM myapp_person') + >>> for p in people: + ... print "%s is %s." % (p.first_name, p.age) + John is 37. + Jane is 42. + ... + +__ http://www.postgresql.org/docs/8.4/static/functions-datetime.html + +Passing parameters into ``raw()`` +--------------------------------- + +If you need to perform parameterized queries, you can use the ``params`` +argument to ``raw()``:: + + >>> lname = 'Doe' + >>> Person.objects.raw('SELECT * FROM myapp_person WHERE last_name = %s', [lname]) + +``params`` is a list of parameters. You'll use ``%s`` placeholders in the +query string (regardless of your database engine); they'll be replaced with +parameters from the ``params`` list. + +.. warning:: + + **Do not use string formatting on raw queries!** + + It's tempting to write the above query as:: + + >>> query = 'SELECT * FROM myapp_person WHERE last_name = %s' % lname + >>> Person.objects.raw(query) + + **Don't.** + + Using the ``params`` list completely protects you from `SQL injection + attacks`__, a common exploit where attackers inject arbitrary SQL into + your database. If you use string interpolation, sooner or later you'll + fall victim to SQL injection. As long as you remember to always use the + ``params`` list you'll be protected. + +__ http://en.wikipedia.org/wiki/SQL_injection + +Executing custom SQL directly +============================= + +Sometimes even :meth:`Manager.raw` isn't quite enough: you might need to +perform queries that don't map cleanly to models, or directly execute +``UPDATE``, ``INSERT``, or ``DELETE`` queries. + +In these cases, you can always access the database directly, routing around +the model layer entirely. + +The object ``django.db.connection`` represents the +default database connection, and ``django.db.transaction`` represents the +default database transaction. To use the database connection, call +``connection.cursor()`` to get a cursor object. Then, call +``cursor.execute(sql, [params])`` to execute the SQL and ``cursor.fetchone()`` +or ``cursor.fetchall()`` to return the resulting rows. After performing a data +changing operation, you should then call +``transaction.commit_unless_managed()`` to ensure your changes are committed +to the database. If your query is purely a data retrieval operation, no commit +is required. For example:: + + def my_custom_sql(): + from django.db import connection, transaction + cursor = connection.cursor() + + # Data modifying operation - commit required + cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz]) + transaction.commit_unless_managed() + + # Data retrieval operation - no commit required + cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz]) + row = cursor.fetchone() + + return row + +If you are using more than one database you can use +``django.db.connections`` to obtain the connection (and cursor) for a +specific database. ``django.db.connections`` is a dictionary-like +object that allows you to retrieve a specific connection using it's +alias:: + + from django.db import connections + cursor = connections['my_db_alias'].cursor() + +.. _transactions-and-raw-sql: + +Transactions and raw SQL +------------------------ +If you are using transaction decorators (such as ``commit_on_success``) to +wrap your views and provide transaction control, you don't have to make a +manual call to ``transaction.commit_unless_managed()`` -- you can manually +commit if you want to, but you aren't required to, since the decorator will +commit for you. However, if you don't manually commit your changes, you will +need to manually mark the transaction as dirty, using +``transaction.set_dirty()``:: + + @commit_on_success + def my_custom_sql_view(request, value): + from django.db import connection, transaction + cursor = connection.cursor() + + # Data modifying operation + cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [value]) + + # Since we modified data, mark the transaction as dirty + transaction.set_dirty() + + # Data retrieval operation. This doesn't dirty the transaction, + # so no call to set_dirty() is required. + cursor.execute("SELECT foo FROM bar WHERE baz = %s", [value]) + row = cursor.fetchone() + + return render_to_response('template.html', {'row': row}) + +The call to ``set_dirty()`` is made automatically when you use the Django ORM +to make data modifying database calls. However, when you use raw SQL, Django +has no way of knowing if your SQL modifies data or not. The manual call to +``set_dirty()`` ensures that Django knows that there are modifications that +must be committed. + +Connections and cursors +----------------------- + +``connection`` and ``cursor`` mostly implement the standard `Python DB-API`_ +(except when it comes to :doc:`transaction handling </topics/db/transactions>`). +If you're not familiar with the Python DB-API, note that the SQL statement in +``cursor.execute()`` uses placeholders, ``"%s"``, rather than adding parameters +directly within the SQL. If you use this technique, the underlying database +library will automatically add quotes and escaping to your parameter(s) as +necessary. (Also note that Django expects the ``"%s"`` placeholder, *not* the +``"?"`` placeholder, which is used by the SQLite Python bindings. This is for +the sake of consistency and sanity.) + +.. _Python DB-API: http://www.python.org/dev/peps/pep-0249/ diff --git a/parts/django/docs/topics/db/transactions.txt b/parts/django/docs/topics/db/transactions.txt new file mode 100644 index 0000000..be9d9a8 --- /dev/null +++ b/parts/django/docs/topics/db/transactions.txt @@ -0,0 +1,328 @@ +============================== +Managing database transactions +============================== + +.. currentmodule:: django.db + +Django gives you a few ways to control how database transactions are managed, +if you're using a database that supports transactions. + +Django's default transaction behavior +===================================== + +Django's default behavior is to run with an open transaction which it +commits automatically when any built-in, data-altering model function is +called. For example, if you call ``model.save()`` or ``model.delete()``, the +change will be committed immediately. + +This is much like the auto-commit setting for most databases. As soon as you +perform an action that needs to write to the database, Django produces the +``INSERT``/``UPDATE``/``DELETE`` statements and then does the ``COMMIT``. +There's no implicit ``ROLLBACK``. + +Tying transactions to HTTP requests +=================================== + +The recommended way to handle transactions in Web requests is to tie them to +the request and response phases via Django's ``TransactionMiddleware``. + +It works like this: When a request starts, Django starts a transaction. If the +response is produced without problems, Django commits any pending transactions. +If the view function produces an exception, Django rolls back any pending +transactions. + +To activate this feature, just add the ``TransactionMiddleware`` middleware to +your :setting:`MIDDLEWARE_CLASSES` setting:: + + MIDDLEWARE_CLASSES = ( + 'django.middleware.cache.UpdateCacheMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.transaction.TransactionMiddleware', + 'django.middleware.cache.FetchFromCacheMiddleware', + ) + +The order is quite important. The transaction middleware applies not only to +view functions, but also for all middleware modules that come after it. So if +you use the session middleware after the transaction middleware, session +creation will be part of the transaction. + +The various cache middlewares are an exception: +:class:`~django.middleware.cache.CacheMiddleware`, +:class:`~django.middleware.cache.UpdateCacheMiddleware`, and +:class:`~django.middleware.cache.FetchFromCacheMiddleware` are never affected. +Even when using database caching, Django's cache backend uses its own +database cursor (which is mapped to its own database connection internally). + +Controlling transaction management in views +=========================================== + +For most people, implicit request-based transactions work wonderfully. However, +if you need more fine-grained control over how transactions are managed, you +can use Python decorators to change the way transactions are handled by a +particular view function. All of the decorators take an option ``using`` +parameter which should be the alias for a database connection for which the +behavior applies to. If no alias is specified then the ``"default"`` database +is used. + +.. note:: + + Although the examples below use view functions as examples, these + decorators can be applied to non-view functions as well. + +.. _topics-db-transactions-autocommit: + +``django.db.transaction.autocommit`` +------------------------------------ + +Use the ``autocommit`` decorator to switch a view function to Django's default +commit behavior, regardless of the global transaction setting. + +Example:: + + from django.db import transaction + + @transaction.autocommit + def viewfunc(request): + .... + + @transaction.autocommit(using="my_other_database") + def viewfunc2(request): + .... + +Within ``viewfunc()``, transactions will be committed as soon as you call +``model.save()``, ``model.delete()``, or any other function that writes to the +database. ``viewfunc2()`` will have this same behavior, but for the +``"my_other_database"`` connection. + +``django.db.transaction.commit_on_success`` +------------------------------------------- + +Use the ``commit_on_success`` decorator to use a single transaction for +all the work done in a function:: + + from django.db import transaction + + @transaction.commit_on_success + def viewfunc(request): + .... + + @transaction.commit_on_success(using="my_other_database") + def viewfunc2(request): + .... + +If the function returns successfully, then Django will commit all work done +within the function at that point. If the function raises an exception, though, +Django will roll back the transaction. + +``django.db.transaction.commit_manually`` +----------------------------------------- + +Use the ``commit_manually`` decorator if you need full control over +transactions. It tells Django you'll be managing the transaction on your own. + +If your view changes data and doesn't ``commit()`` or ``rollback()``, Django +will raise a ``TransactionManagementError`` exception. + +Manual transaction management looks like this:: + + from django.db import transaction + + @transaction.commit_manually + def viewfunc(request): + ... + # You can commit/rollback however and whenever you want + transaction.commit() + ... + + # But you've got to remember to do it yourself! + try: + ... + except: + transaction.rollback() + else: + transaction.commit() + + @transaction.commit_manually(using="my_other_database") + def viewfunc2(request): + .... + +.. admonition:: An important note to users of earlier Django releases: + + The database ``connection.commit()`` and ``connection.rollback()`` methods + (called ``db.commit()`` and ``db.rollback()`` in 0.91 and earlier) no + longer exist. They've been replaced by ``transaction.commit()`` and + ``transaction.rollback()``. + +How to globally deactivate transaction management +================================================= + +Control freaks can totally disable all transaction management by setting +``DISABLE_TRANSACTION_MANAGEMENT`` to ``True`` in the Django settings file. + +If you do this, Django won't provide any automatic transaction management +whatsoever. Middleware will no longer implicitly commit transactions, and +you'll need to roll management yourself. This even requires you to commit +changes done by middleware somewhere else. + +Thus, this is best used in situations where you want to run your own +transaction-controlling middleware or do something really strange. In almost +all situations, you'll be better off using the default behavior, or the +transaction middleware, and only modify selected functions as needed. + +.. _topics-db-transactions-savepoints: + +Savepoints +========== + +A savepoint is a marker within a transaction that enables you to roll back +part of a transaction, rather than the full transaction. Savepoints are +available to the PostgreSQL 8 and Oracle backends. Other backends will +provide the savepoint functions, but they are empty operations - they won't +actually do anything. + +Savepoints aren't especially useful if you are using the default +``autocommit`` behaviour of Django. However, if you are using +``commit_on_success`` or ``commit_manually``, each open transaction will build +up a series of database operations, awaiting a commit or rollback. If you +issue a rollback, the entire transaction is rolled back. Savepoints provide +the ability to perform a fine-grained rollback, rather than the full rollback +that would be performed by ``transaction.rollback()``. + +Each of these functions takes a ``using`` argument which should be the name of +a database for which the behavior applies. If no ``using`` argument is +provided then the ``"default"`` database is used. + +Savepoints are controlled by three methods on the transaction object: + +.. method:: transaction.savepoint(using=None) + + Creates a new savepoint. This marks a point in the transaction that + is known to be in a "good" state. + + Returns the savepoint ID (sid). + +.. method:: transaction.savepoint_commit(sid, using=None) + + Updates the savepoint to include any operations that have been performed + since the savepoint was created, or since the last commit. + +.. method:: transaction.savepoint_rollback(sid, using=None) + + Rolls the transaction back to the last point at which the savepoint was + committed. + +The following example demonstrates the use of savepoints:: + + from django.db import transaction + + @transaction.commit_manually + def viewfunc(request): + + a.save() + # open transaction now contains a.save() + sid = transaction.savepoint() + + b.save() + # open transaction now contains a.save() and b.save() + + if want_to_keep_b: + transaction.savepoint_commit(sid) + # open transaction still contains a.save() and b.save() + else: + transaction.savepoint_rollback(sid) + # open transaction now contains only a.save() + + transaction.commit() + +Transactions in MySQL +===================== + +If you're using MySQL, your tables may or may not support transactions; it +depends on your MySQL version and the table types you're using. (By +"table types," we mean something like "InnoDB" or "MyISAM".) MySQL transaction +peculiarities are outside the scope of this article, but the MySQL site has +`information on MySQL transactions`_. + +If your MySQL setup does *not* support transactions, then Django will function +in auto-commit mode: Statements will be executed and committed as soon as +they're called. If your MySQL setup *does* support transactions, Django will +handle transactions as explained in this document. + +.. _information on MySQL transactions: http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-transactions.html + +Handling exceptions within PostgreSQL transactions +================================================== + +When a call to a PostgreSQL cursor raises an exception (typically +``IntegrityError``), all subsequent SQL in the same transaction will fail with +the error "current transaction is aborted, queries ignored until end of +transaction block". Whilst simple use of ``save()`` is unlikely to raise an +exception in PostgreSQL, there are more advanced usage patterns which +might, such as saving objects with unique fields, saving using the +force_insert/force_update flag, or invoking custom SQL. + +There are several ways to recover from this sort of error. + +Transaction rollback +-------------------- + +The first option is to roll back the entire transaction. For example:: + + a.save() # Succeeds, but may be undone by transaction rollback + try: + b.save() # Could throw exception + except IntegrityError: + transaction.rollback() + c.save() # Succeeds, but a.save() may have been undone + +Calling ``transaction.rollback()`` rolls back the entire transaction. Any +uncommitted database operations will be lost. In this example, the changes +made by ``a.save()`` would be lost, even though that operation raised no error +itself. + +Savepoint rollback +------------------ + +If you are using PostgreSQL 8 or later, you can use :ref:`savepoints +<topics-db-transactions-savepoints>` to control the extent of a rollback. +Before performing a database operation that could fail, you can set or update +the savepoint; that way, if the operation fails, you can roll back the single +offending operation, rather than the entire transaction. For example:: + + a.save() # Succeeds, and never undone by savepoint rollback + try: + sid = transaction.savepoint() + b.save() # Could throw exception + transaction.savepoint_commit(sid) + except IntegrityError: + transaction.savepoint_rollback(sid) + c.save() # Succeeds, and a.save() is never undone + +In this example, ``a.save()`` will not be undone in the case where +``b.save()`` raises an exception. + +Database-level autocommit +------------------------- + +.. versionadded:: 1.1 + +With PostgreSQL 8.2 or later, there is an advanced option to run PostgreSQL +with :doc:`database-level autocommit </ref/databases>`. If you use this option, +there is no constantly open transaction, so it is always possible to continue +after catching an exception. For example:: + + a.save() # succeeds + try: + b.save() # Could throw exception + except IntegrityError: + pass + c.save() # succeeds + +.. note:: + + This is not the same as the :ref:`autocommit decorator + <topics-db-transactions-autocommit>`. When using database level autocommit + there is no database transaction at all. The ``autocommit`` decorator + still uses transactions, automatically committing each transaction when + a database modifying operation occurs. diff --git a/parts/django/docs/topics/email.txt b/parts/django/docs/topics/email.txt new file mode 100644 index 0000000..36bebfb --- /dev/null +++ b/parts/django/docs/topics/email.txt @@ -0,0 +1,618 @@ +============== +Sending e-mail +============== + +.. module:: django.core.mail + :synopsis: Helpers to easily send e-mail. + +Although Python makes sending e-mail relatively easy via the `smtplib +library`_, Django provides a couple of light wrappers over it. These wrappers +are provided to make sending e-mail extra quick, to make it easy to test +e-mail sending during development, and to provide support for platforms that +can't use SMTP. + +The code lives in the ``django.core.mail`` module. + +.. _smtplib library: http://docs.python.org/library/smtplib.html + +Quick example +============= + +In two lines:: + + from django.core.mail import send_mail + + send_mail('Subject here', 'Here is the message.', 'from@example.com', + ['to@example.com'], fail_silently=False) + +Mail is sent using the SMTP host and port specified in the +:setting:`EMAIL_HOST` and :setting:`EMAIL_PORT` settings. The +:setting:`EMAIL_HOST_USER` and :setting:`EMAIL_HOST_PASSWORD` settings, if +set, are used to authenticate to the SMTP server, and the +:setting:`EMAIL_USE_TLS` setting controls whether a secure connection is used. + +.. note:: + + The character set of e-mail sent with ``django.core.mail`` will be set to + the value of your :setting:`DEFAULT_CHARSET` setting. + +send_mail() +=========== + +.. function:: send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None) + +The simplest way to send e-mail is using +``django.core.mail.send_mail()``. + +The ``subject``, ``message``, ``from_email`` and ``recipient_list`` parameters +are required. + + * ``subject``: A string. + * ``message``: A string. + * ``from_email``: A string. + * ``recipient_list``: A list of strings, each an e-mail address. Each + member of ``recipient_list`` will see the other recipients in the "To:" + field of the e-mail message. + * ``fail_silently``: A boolean. If it's ``False``, ``send_mail`` will raise + an ``smtplib.SMTPException``. See the `smtplib docs`_ for a list of + possible exceptions, all of which are subclasses of ``SMTPException``. + * ``auth_user``: The optional username to use to authenticate to the SMTP + server. If this isn't provided, Django will use the value of the + :setting:`EMAIL_HOST_USER` setting. + * ``auth_password``: The optional password to use to authenticate to the + SMTP server. If this isn't provided, Django will use the value of the + :setting:`EMAIL_HOST_PASSWORD` setting. + * ``connection``: The optional e-mail backend to use to send the mail. + If unspecified, an instance of the default backend will be used. + See the documentation on :ref:`E-mail backends <topic-email-backends>` + for more details. + +.. _smtplib docs: http://docs.python.org/library/smtplib.html + +send_mass_mail() +================ + +.. function:: send_mass_mail(datatuple, fail_silently=False, auth_user=None, auth_password=None, connection=None) + +``django.core.mail.send_mass_mail()`` is intended to handle mass e-mailing. + +``datatuple`` is a tuple in which each element is in this format:: + + (subject, message, from_email, recipient_list) + +``fail_silently``, ``auth_user`` and ``auth_password`` have the same functions +as in :meth:`~django.core.mail.send_mail()`. + +Each separate element of ``datatuple`` results in a separate e-mail message. +As in :meth:`~django.core.mail.send_mail()`, recipients in the same +``recipient_list`` will all see the other addresses in the e-mail messages' +"To:" field. + +For example, the following code would send two different messages to +two different sets of recipients; however, only one connection to the +mail server would be opened:: + + message1 = ('Subject here', 'Here is the message', 'from@example.com, ['first@example.com', 'other@example.com']) + message2 = ('Another Subject', 'Here is another message', 'from@example.com', ['second@test.com']) + send_mass_mail((message1, message2), fail_silently=False) + +send_mass_mail() vs. send_mail() +-------------------------------- + +The main difference between :meth:`~django.core.mail.send_mass_mail()` and +:meth:`~django.core.mail.send_mail()` is that +:meth:`~django.core.mail.send_mail()` opens a connection to the mail server +each time it's executed, while :meth:`~django.core.mail.send_mass_mail()` uses +a single connection for all of its messages. This makes +:meth:`~django.core.mail.send_mass_mail()` slightly more efficient. + +mail_admins() +============= + +.. function:: mail_admins(subject, message, fail_silently=False, connection=None) + +``django.core.mail.mail_admins()`` is a shortcut for sending an e-mail to the +site admins, as defined in the :setting:`ADMINS` setting. + +``mail_admins()`` prefixes the subject with the value of the +:setting:`EMAIL_SUBJECT_PREFIX` setting, which is ``"[Django] "`` by default. + +The "From:" header of the e-mail will be the value of the +:setting:`SERVER_EMAIL` setting. + +This method exists for convenience and readability. + +mail_managers() +=============== + +.. function:: mail_managers(subject, message, fail_silently=False, connection=None) + +``django.core.mail.mail_managers()`` is just like ``mail_admins()``, except it +sends an e-mail to the site managers, as defined in the :setting:`MANAGERS` +setting. + +Examples +======== + +This sends a single e-mail to john@example.com and jane@example.com, with them +both appearing in the "To:":: + + send_mail('Subject', 'Message.', 'from@example.com', + ['john@example.com', 'jane@example.com']) + +This sends a message to john@example.com and jane@example.com, with them both +receiving a separate e-mail:: + + datatuple = ( + ('Subject', 'Message.', 'from@example.com', ['john@example.com']), + ('Subject', 'Message.', 'from@example.com', ['jane@example.com']), + ) + send_mass_mail(datatuple) + +Preventing header injection +=========================== + +`Header injection`_ is a security exploit in which an attacker inserts extra +e-mail headers to control the "To:" and "From:" in e-mail messages that your +scripts generate. + +The Django e-mail functions outlined above all protect against header injection +by forbidding newlines in header values. If any ``subject``, ``from_email`` or +``recipient_list`` contains a newline (in either Unix, Windows or Mac style), +the e-mail function (e.g. :meth:`~django.core.mail.send_mail()`) will raise +``django.core.mail.BadHeaderError`` (a subclass of ``ValueError``) and, hence, +will not send the e-mail. It's your responsibility to validate all data before +passing it to the e-mail functions. + +If a ``message`` contains headers at the start of the string, the headers will +simply be printed as the first bit of the e-mail message. + +Here's an example view that takes a ``subject``, ``message`` and ``from_email`` +from the request's POST data, sends that to admin@example.com and redirects to +"/contact/thanks/" when it's done:: + + from django.core.mail import send_mail, BadHeaderError + + def send_email(request): + subject = request.POST.get('subject', '') + message = request.POST.get('message', '') + from_email = request.POST.get('from_email', '') + if subject and message and from_email: + try: + send_mail(subject, message, from_email, ['admin@example.com']) + except BadHeaderError: + return HttpResponse('Invalid header found.') + return HttpResponseRedirect('/contact/thanks/') + else: + # In reality we'd use a form class + # 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 + +.. _emailmessage-and-smtpconnection: + +The EmailMessage class +====================== + +.. versionadded:: 1.0 + +Django's :meth:`~django.core.mail.send_mail()` and +:meth:`~django.core.mail.send_mass_mail()` functions are actually thin +wrappers that make use of the :class:`~django.core.mail.EmailMessage` class. + +Not all features of the :class:`~django.core.mail.EmailMessage` class are +available through the :meth:`~django.core.mail.send_mail()` and related +wrapper functions. If you wish to use advanced features, such as BCC'ed +recipients, file attachments, or multi-part e-mail, you'll need to create +:class:`~django.core.mail.EmailMessage` instances directly. + +.. note:: + This is a design feature. :meth:`~django.core.mail.send_mail()` and + related functions were originally the only interface Django provided. + However, the list of parameters they accepted was slowly growing over + time. It made sense to move to a more object-oriented design for e-mail + messages and retain the original functions only for backwards + compatibility. + +:class:`~django.core.mail.EmailMessage` is responsible for creating the e-mail +message itself. The :ref:`e-mail backend <topic-email-backends>` is then +responsible for sending the e-mail. + +For convenience, :class:`~django.core.mail.EmailMessage` provides a simple +``send()`` method for sending a single e-mail. If you need to send multiple +messages, the e-mail backend API :ref:`provides an alternative +<topics-sending-multiple-emails>`. + +EmailMessage Objects +-------------------- + +.. class:: EmailMessage + +The :class:`~django.core.mail.EmailMessage` class is initialized with the +following parameters (in the given order, if positional arguments are used). +All parameters are optional and can be set at any time prior to calling the +``send()`` method. + + * ``subject``: The subject line of the e-mail. + + * ``body``: The body text. This should be a plain text message. + + * ``from_email``: The sender's address. Both ``fred@example.com`` and + ``Fred <fred@example.com>`` forms are legal. If omitted, the + :setting:`DEFAULT_FROM_EMAIL` setting is used. + + * ``to``: A list or tuple of recipient addresses. + + * ``bcc``: A list or tuple of addresses used in the "Bcc" header when + sending the e-mail. + + * ``connection``: An e-mail backend instance. Use this parameter if + you want to use the same connection for multiple messages. If omitted, a + new connection is created when ``send()`` is called. + + * ``attachments``: A list of attachments to put on the message. These can + be either ``email.MIMEBase.MIMEBase`` instances, or ``(filename, + content, mimetype)`` triples. + + * ``headers``: A dictionary of extra headers to put on the message. The + keys are the header name, values are the header values. It's up to the + caller to ensure header names and values are in the correct format for + an e-mail message. + +For example:: + + email = EmailMessage('Hello', 'Body goes here', 'from@example.com', + ['to1@example.com', 'to2@example.com'], ['bcc@example.com'], + headers = {'Reply-To': 'another@example.com'}) + +The class has the following methods: + + * ``send(fail_silently=False)`` sends the message. If a connection was + specified when the e-mail was constructed, that connection will be used. + Otherwise, an instance of the default backend will be instantiated and + used. If the keyword argument ``fail_silently`` is ``True``, exceptions + raised while sending the message will be quashed. + + * ``message()`` constructs a ``django.core.mail.SafeMIMEText`` object (a + subclass of Python's ``email.MIMEText.MIMEText`` class) or a + ``django.core.mail.SafeMIMEMultipart`` object holding the message to be + sent. If you ever need to extend the + :class:`~django.core.mail.EmailMessage` class, you'll probably want to + override this method to put the content you want into the MIME object. + + * ``recipients()`` returns a list of all the recipients of the message, + whether they're recorded in the ``to`` or ``bcc`` attributes. This is + another method you might need to override when subclassing, because the + SMTP server needs to be told the full list of recipients when the message + is sent. If you add another way to specify recipients in your class, they + need to be returned from this method as well. + + * ``attach()`` creates a new file attachment and adds it to the message. + There are two ways to call ``attach()``: + + * You can pass it a single argument that is an + ``email.MIMEBase.MIMEBase`` instance. This will be inserted directly + into the resulting message. + + * Alternatively, you can pass ``attach()`` three arguments: + ``filename``, ``content`` and ``mimetype``. ``filename`` is the name + of the file attachment as it will appear in the e-mail, ``content`` is + the data that will be contained inside the attachment and + ``mimetype`` is the optional MIME type for the attachment. If you + omit ``mimetype``, the MIME content type will be guessed from the + filename of the attachment. + + For example:: + + message.attach('design.png', img_data, 'image/png') + + * ``attach_file()`` creates a new attachment using a file from your + filesystem. Call it with the path of the file to attach and, optionally, + the MIME type to use for the attachment. If the MIME type is omitted, it + will be guessed from the filename. The simplest use would be:: + + message.attach_file('/images/weather_map.png') + +.. _DEFAULT_FROM_EMAIL: ../settings/#default-from-email + +Sending alternative content types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It can be useful to include multiple versions of the content in an e-mail; the +classic example is to send both text and HTML versions of a message. With +Django's e-mail library, you can do this using the ``EmailMultiAlternatives`` +class. This subclass of :class:`~django.core.mail.EmailMessage` has an +``attach_alternative()`` method for including extra versions of the message +body in the e-mail. All the other methods (including the class initialization) +are inherited directly from :class:`~django.core.mail.EmailMessage`. + +To send a text and HTML combination, you could write:: + + from django.core.mail import EmailMultiAlternatives + + subject, from_email, to = 'hello', 'from@example.com', 'to@example.com' + text_content = 'This is an important message.' + html_content = '<p>This is an <strong>important</strong> message.</p>' + msg = EmailMultiAlternatives(subject, text_content, from_email, [to]) + msg.attach_alternative(html_content, "text/html") + msg.send() + +By default, the MIME type of the ``body`` parameter in an +:class:`~django.core.mail.EmailMessage` is ``"text/plain"``. It is good +practice to leave this alone, because it guarantees that any recipient will be +able to read the e-mail, regardless of their mail client. However, if you are +confident that your recipients can handle an alternative content type, you can +use the ``content_subtype`` attribute on the +:class:`~django.core.mail.EmailMessage` class to change the main content type. +The major type will always be ``"text"``, but you can change the +subtype. For example:: + + msg = EmailMessage(subject, html_content, from_email, [to]) + msg.content_subtype = "html" # Main content is now text/html + msg.send() + +.. _topic-email-backends: + +E-Mail Backends +=============== + +.. versionadded:: 1.2 + +The actual sending of an e-mail is handled by the e-mail backend. + +The e-mail backend class has the following methods: + + * ``open()`` instantiates an long-lived e-mail-sending connection. + + * ``close()`` closes the current e-mail-sending connection. + + * ``send_messages(email_messages)`` sends a list of + :class:`~django.core.mail.EmailMessage` objects. If the connection is + not open, this call will implicitly open the connection, and close the + connection afterwards. If the connection is already open, it will be + left open after mail has been sent. + +Obtaining an instance of an e-mail backend +------------------------------------------ + +The :meth:`get_connection` function in ``django.core.mail`` returns an +instance of the e-mail backend that you can use. + +.. currentmodule:: django.core.mail + +.. function:: get_connection(backend=None, fail_silently=False, *args, **kwargs) + +By default, a call to ``get_connection()`` will return an instance of the +e-mail backend specified in :setting:`EMAIL_BACKEND`. If you specify the +``backend`` argument, an instance of that backend will be instantiated. + +The ``fail_silently`` argument controls how the backend should handle errors. +If ``fail_silently`` is True, exceptions during the e-mail sending process +will be silently ignored. + +All other arguments are passed directly to the constructor of the +e-mail backend. + +Django ships with several e-mail sending backends. With the exception of the +SMTP backend (which is the default), these backends are only useful during +testing and development. If you have special e-mail sending requirements, you +can :ref:`write your own e-mail backend <topic-custom-email-backend>`. + +.. _topic-email-smtp-backend: + +SMTP backend +~~~~~~~~~~~~ + +This is the default backend. E-mail will be sent through a SMTP server. +The server address and authentication credentials are set in the +:setting:`EMAIL_HOST`, :setting:`EMAIL_PORT`, :setting:`EMAIL_HOST_USER`, +:setting:`EMAIL_HOST_PASSWORD` and :setting:`EMAIL_USE_TLS` settings in your +settings file. + +The SMTP backend is the default configuration inherited by Django. If you +want to specify it explicitly, put the following in your settings:: + + EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' + +.. admonition:: SMTPConnection objects + + Prior to version 1.2, Django provided a + :class:`~django.core.mail.SMTPConnection` class. This class provided a way + to directly control the use of SMTP to send e-mail. This class has been + deprecated in favor of the generic e-mail backend API. + + For backwards compatibility :class:`~django.core.mail.SMTPConnection` is + still available in ``django.core.mail`` as an alias for the SMTP backend. + New code should use :meth:`~django.core.mail.get_connection` instead. + +.. _topic-email-console-backend: + +Console backend +~~~~~~~~~~~~~~~ + +Instead of sending out real e-mails the console backend just writes the +e-mails that would be send to the standard output. By default, the console +backend writes to ``stdout``. You can use a different stream-like object by +providing the ``stream`` keyword argument when constructing the connection. + +To specify this backend, put the following in your settings:: + + EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' + +This backend is not intended for use in production -- it is provided as a +convenience that can be used during development. + +.. _topic-email-file-backend: + +File backend +~~~~~~~~~~~~ + +The file backend writes e-mails to a file. A new file is created for each new +session that is opened on this backend. The directory to which the files are +written is either taken from the :setting:`EMAIL_FILE_PATH` setting or from +the ``file_path`` keyword when creating a connection with +:meth:`~django.core.mail.get_connection`. + +To specify this backend, put the following in your settings:: + + EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend' + EMAIL_FILE_PATH = '/tmp/app-messages' # change this to a proper location + +This backend is not intended for use in production -- it is provided as a +convenience that can be used during development. + +.. _topic-email-memory-backend: + +In-memory backend +~~~~~~~~~~~~~~~~~ + +The ``'locmem'`` backend stores messages in a special attribute of the +``django.core.mail`` module. The ``outbox`` attribute is created when the +first message is sent. It's a list with an +:class:`~django.core.mail.EmailMessage` instance for each message that would +be send. + +To specify this backend, put the following in your settings:: + + EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend' + +This backend is not intended for use in production -- it is provided as a +convenience that can be used during development and testing. + +.. _topic-email-dummy-backend: + +Dummy backend +~~~~~~~~~~~~~ + +As the name suggests the dummy backend does nothing with your messages. To +specify this backend, put the following in your settings:: + + EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend' + +This backend is not intended for use in production -- it is provided as a +convenience that can be used during development. + +.. _topic-custom-email-backend: + +Defining a custom e-mail backend +-------------------------------- + +If you need to change how e-mails are sent you can write your own e-mail +backend. The ``EMAIL_BACKEND`` setting in your settings file is then the +Python import path for your backend class. + +Custom e-mail backends should subclass ``BaseEmailBackend`` that is located in +the ``django.core.mail.backends.base`` module. A custom e-mail backend must +implement the ``send_messages(email_messages)`` method. This method receives a +list of :class:`~django.core.mail.EmailMessage` instances and returns the +number of successfully delivered messages. If your backend has any concept of +a persistent session or connection, you should also implement the ``open()`` +and ``close()`` methods. Refer to ``smtp.EmailBackend`` for a reference +implementation. + +.. _topics-sending-multiple-emails: + +Sending multiple e-mails +------------------------ + +Establishing and closing an SMTP connection (or any other network connection, +for that matter) is an expensive process. If you have a lot of e-mails to send, +it makes sense to reuse an SMTP connection, rather than creating and +destroying a connection every time you want to send an e-mail. + +There are two ways you tell an e-mail backend to reuse a connection. + +Firstly, you can use the ``send_messages()`` method. ``send_messages()`` takes +a list of :class:`~django.core.mail.EmailMessage` instances (or subclasses), +and sends them all using a single connection. + +For example, if you have a function called ``get_notification_email()`` that +returns a list of :class:`~django.core.mail.EmailMessage` objects representing +some periodic e-mail you wish to send out, you could send these e-mails using +a single call to send_messages:: + + from django.core import mail + connection = mail.get_connection() # Use default e-mail connection + messages = get_notification_email() + connection.send_messages(messages) + +In this example, the call to ``send_messages()`` opens a connection on the +backend, sends the list of messages, and then closes the connection again. + +The second approach is to use the ``open()`` and ``close()`` methods on the +e-mail backend to manually control the connection. ``send_messages()`` will not +manually open or close the connection if it is already open, so if you +manually open the connection, you can control when it is closed. For example:: + + from django.core import mail + connection = mail.get_connection() + + # Manually open the connection + connection.open() + + # Construct an e-mail message that uses the connection + email1 = mail.EmailMessage('Hello', 'Body goes here', 'from@example.com', + ['to1@example.com'], connection=connection) + email1.send() # Send the e-mail + + # Construct two more messages + email2 = mail.EmailMessage('Hello', 'Body goes here', 'from@example.com', + ['to2@example.com']) + email3 = mail.EmailMessage('Hello', 'Body goes here', 'from@example.com', + ['to3@example.com']) + + # Send the two e-mails in a single call - + connection.send_messages([email2, email3]) + # The connection was already open so send_messages() doesn't close it. + # We need to manually close the connection. + connection.close() + + +Testing e-mail sending +====================== + +There are times when you do not want Django to send e-mails at +all. For example, while developing a Web site, you probably don't want +to send out thousands of e-mails -- but you may want to validate that +e-mails will be sent to the right people under the right conditions, +and that those e-mails will contain the correct content. + +The easiest way to test your project's use of e-mail is to use the ``console`` +e-mail backend. This backend redirects all e-mail to stdout, allowing you to +inspect the content of mail. + +The ``file`` e-mail backend can also be useful during development -- this backend +dumps the contents of every SMTP connection to a file that can be inspected +at your leisure. + +Another approach is to use a "dumb" SMTP server that receives the e-mails +locally and displays them to the terminal, but does not actually send +anything. Python has a built-in way to accomplish this with a single command:: + + python -m smtpd -n -c DebuggingServer localhost:1025 + +This command will start a simple SMTP server listening on port 1025 of +localhost. This server simply prints to standard output all e-mail headers and +the e-mail body. You then only need to set the :setting:`EMAIL_HOST` and +:setting:`EMAIL_PORT` accordingly, and you are set. + +For a more detailed discussion of testing and processing of e-mails locally, +see the Python documentation on the `SMTP Server`_. + +.. _SMTP Server: http://docs.python.org/library/smtpd.html + +SMTPConnection +============== + +.. class:: SMTPConnection + +.. deprecated:: 1.2 + +The ``SMTPConnection`` class has been deprecated in favor of the generic e-mail +backend API. + +For backwards compatibility ``SMTPConnection`` is still available in +``django.core.mail`` as an alias for the :ref:`SMTP backend +<topic-email-smtp-backend>`. New code should use +:meth:`~django.core.mail.get_connection` instead. diff --git a/parts/django/docs/topics/files.txt b/parts/django/docs/topics/files.txt new file mode 100644 index 0000000..d1926c6 --- /dev/null +++ b/parts/django/docs/topics/files.txt @@ -0,0 +1,147 @@ +============== +Managing files +============== + +.. versionadded:: 1.0 + +This document describes Django's file access APIs. + +By default, Django stores files locally, using the :setting:`MEDIA_ROOT` and +:setting:`MEDIA_URL` settings. The examples below assume that you're using these +defaults. + +However, Django provides ways to write custom `file storage systems`_ that +allow you to completely customize where and how Django stores files. The +second half of this document describes how these storage systems work. + +.. _file storage systems: `File storage`_ + +Using files in models +===================== + +When you use a :class:`~django.db.models.FileField` or +:class:`~django.db.models.ImageField`, Django provides a set of APIs you can use +to deal with that file. + +Consider the following model, using an :class:`~django.db.models.ImageField` to +store a photo:: + + class Car(models.Model): + name = models.CharField(max_length=255) + price = models.DecimalField(max_digits=5, decimal_places=2) + photo = models.ImageField(upload_to='cars') + +Any ``Car`` instance will have a ``photo`` attribute that you can use to get at +the details of the attached photo:: + + >>> car = Car.objects.get(name="57 Chevy") + >>> car.photo + <ImageFieldFile: chevy.jpg> + >>> car.photo.name + u'cars/chevy.jpg' + >>> car.photo.path + u'/media/cars/chevy.jpg' + >>> car.photo.url + u'http://media.example.com/cars/chevy.jpg' + +This object -- ``car.photo`` in the example -- is a ``File`` object, which means +it has all the methods and attributes described below. + +The ``File`` object +=================== + +Internally, Django uses a :class:`django.core.files.File` instance any time it +needs to represent a file. This object is a thin wrapper around Python's +`built-in file object`_ with some Django-specific additions. + +.. _built-in file object: http://docs.python.org/library/stdtypes.html#bltin-file-objects + +Most of the time you'll simply use a ``File`` that Django's given you (i.e. a +file attached to a model as above, or perhaps an uploaded file). + +If you need to construct a ``File`` yourself, the easiest way is to create one +using a Python built-in ``file`` object:: + + >>> from django.core.files import File + + # Create a Python file object using open() + >>> f = open('/tmp/hello.world', 'w') + >>> myfile = File(f) + +Now you can use any of the documented attributes and methods +of the :class:`~django.core.files.File` class. + +File storage +============ + +Behind the scenes, Django delegates decisions about how and where to store files +to a file storage system. This is the object that actually understands things +like file systems, opening and reading files, etc. + +Django's default file storage is given by the :setting:`DEFAULT_FILE_STORAGE` +setting; if you don't explicitly provide a storage system, this is the one that +will be used. + +See below for details of the built-in default file storage system, and see +:doc:`/howto/custom-file-storage` for information on writing your own file +storage system. + +Storage objects +--------------- + +Though most of the time you'll want to use a ``File`` object (which delegates to +the proper storage for that file), you can use file storage systems directly. +You can create an instance of some custom file storage class, or -- often more +useful -- you can use the global default storage system:: + + >>> from django.core.files.storage import default_storage + >>> from django.core.files.base import ContentFile + + >>> path = default_storage.save('/path/to/file', ContentFile('new content')) + >>> path + u'/path/to/file' + + >>> default_storage.size(path) + 11 + >>> default_storage.open(path).read() + 'new content' + + >>> default_storage.delete(path) + >>> default_storage.exists(path) + False + +See :doc:`/ref/files/storage` for the file storage API. + +The built-in filesystem storage class +------------------------------------- + +Django ships with a built-in ``FileSystemStorage`` class (defined in +``django.core.files.storage``) which implements basic local filesystem file +storage. Its initializer takes two arguments: + +====================== =================================================== +Argument Description +====================== =================================================== +``location`` Optional. Absolute path to the directory that will + hold the files. If omitted, it will be set to the + value of your :setting:`MEDIA_ROOT` setting. +``base_url`` Optional. URL that serves the files stored at this + location. If omitted, it will default to the value + of your :setting:`MEDIA_URL` setting. +====================== =================================================== + +For example, the following code will store uploaded files under +``/media/photos`` regardless of what your :setting:`MEDIA_ROOT` setting is:: + + from django.db import models + from django.core.files.storage import FileSystemStorage + + fs = FileSystemStorage(location='/media/photos') + + class Car(models.Model): + ... + photo = models.ImageField(storage=fs) + +:doc:`Custom storage systems </howto/custom-file-storage>` work the same way: +you can pass them in as the ``storage`` argument to a +:class:`~django.db.models.FileField`. diff --git a/parts/django/docs/topics/forms/formsets.txt b/parts/django/docs/topics/forms/formsets.txt new file mode 100644 index 0000000..72296bc --- /dev/null +++ b/parts/django/docs/topics/forms/formsets.txt @@ -0,0 +1,440 @@ +.. _formsets: + +Formsets +======== + +A formset is a layer of abstraction to working with multiple forms on the same +page. It can be best compared to a data grid. Let's say you have the following +form:: + + >>> from django import forms + >>> class ArticleForm(forms.Form): + ... title = forms.CharField() + ... pub_date = forms.DateField() + +You might want to allow the user to create several articles at once. To create +a formset out of an ``ArticleForm`` you would do:: + + >>> from django.forms.formsets import formset_factory + >>> ArticleFormSet = formset_factory(ArticleForm) + +You now have created a formset named ``ArticleFormSet``. The formset gives you +the ability to iterate over the forms in the formset and display them as you +would with a regular form:: + + >>> formset = ArticleFormSet() + >>> for form in formset.forms: + ... print form.as_table() + <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> + +As you can see it only displayed one empty form. The number of empty forms +that is displayed is controlled by the ``extra`` parameter. By default, +``formset_factory`` defines one extra form; the following example will +display two blank forms:: + + >>> ArticleFormSet = formset_factory(ArticleForm, extra=2) + +Using initial data with a formset +--------------------------------- + +Initial data is what drives the main usability of a formset. As shown above +you can define the number of extra forms. What this means is that you are +telling the formset how many additional forms to show in addition to the +number of forms it generates from the initial data. Lets take a look at an +example:: + + >>> ArticleFormSet = formset_factory(ArticleForm, extra=2) + >>> formset = ArticleFormSet(initial=[ + ... {'title': u'Django is now open source', + ... 'pub_date': datetime.date.today()}, + ... ]) + + >>> for form in formset.forms: + ... print form.as_table() + <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Django is now open source" 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" value="2008-05-12" id="id_form-0-pub_date" /></td></tr> + <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" id="id_form-1-title" /></td></tr> + <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" id="id_form-1-pub_date" /></td></tr> + <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr> + <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr> + +There are now a total of three forms showing above. One for the initial data +that was passed in and two extra forms. Also note that we are passing in a +list of dictionaries as the initial data. + +.. seealso:: + + :ref:`Creating formsets from models with model formsets <model-formsets>`. + +.. _formsets-max-num: + +Limiting the maximum number of forms +------------------------------------ + +The ``max_num`` parameter to ``formset_factory`` gives you the ability to +limit the maximum number of empty forms the formset will display:: + + >>> ArticleFormSet = formset_factory(ArticleForm, extra=2, max_num=1) + >>> formset = ArticleFormset() + >>> for form in formset.forms: + ... print form.as_table() + <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. + +Formset validation +------------------ + +Validation with a formset is almost identical to a regular ``Form``. There is +an ``is_valid`` method on the formset to provide a convenient way to validate +all forms in the formset:: + + >>> ArticleFormSet = formset_factory(ArticleForm) + >>> formset = ArticleFormSet({}) + >>> formset.is_valid() + True + +We passed in no data to the formset which is resulting in a valid form. The +formset is smart enough to ignore extra forms that were not changed. If we +provide an invalid article:: + + >>> data = { + ... 'form-TOTAL_FORMS': u'2', + ... 'form-INITIAL_FORMS': u'0', + ... 'form-MAX_NUM_FORMS': u'', + ... 'form-0-title': u'Test', + ... 'form-0-pub_date': u'16 June 1904', + ... 'form-1-title': u'Test', + ... 'form-1-pub_date': u'', # <-- this date is missing but required + ... } + >>> formset = ArticleFormSet(data) + >>> formset.is_valid() + False + >>> formset.errors + [{}, {'pub_date': [u'This field is required.']}] + +As we can see, ``formset.errors`` is a list whose entries correspond to the +forms in the formset. Validation was performed for each of the two forms, and +the expected error message appears for the second item. + +.. _understanding-the-managementform: + +Understanding the ManagementForm +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You may have noticed the additional data (``form-TOTAL_FORMS``, +``form-INITIAL_FORMS`` and ``form-MAX_NUM_FORMS``) that was required +in the formset's data above. This data is required for the +``ManagementForm``. This form is used by the formset to manage the +collection of forms contained in the formset. If you don't provide +this management data, an exception will be raised:: + + >>> data = { + ... 'form-0-title': u'Test', + ... 'form-0-pub_date': u'', + ... } + >>> formset = ArticleFormSet(data) + Traceback (most recent call last): + ... + django.forms.util.ValidationError: [u'ManagementForm data is missing or has been tampered with'] + +It is used to keep track of how many form instances are being displayed. If +you are adding new forms via JavaScript, you should increment the count fields +in this form as well. + +The management form is available as an attribute of the formset +itself. When rendering a formset in a template, you can include all +the management data by rendering ``{{ my_formset.management_form }}`` +(substituting the name of your formset as appropriate). + +.. versionadded:: 1.1 + +``total_form_count`` and ``initial_form_count`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``BaseFormSet`` has a couple of methods that are closely related to the +``ManagementForm``, ``total_form_count`` and ``initial_form_count``. + +``total_form_count`` returns the total number of forms in this formset. +``initial_form_count`` returns the number of forms in the formset that were +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`` +~~~~~~~~~~~~~~ + +``BaseFormSet`` provides an additional attribute ``empty_form`` which returns +a form instance with a prefix of ``__prefix__`` for easier use in dynamic +forms with JavaScript. + +Custom formset validation +~~~~~~~~~~~~~~~~~~~~~~~~~ + +A formset has a ``clean`` method similar to the one on a ``Form`` class. This +is where you define your own validation that works at the formset level:: + + >>> from django.forms.formsets import BaseFormSet + + >>> class BaseArticleFormSet(BaseFormSet): + ... def clean(self): + ... """Checks that no two articles have the same title.""" + ... if any(self.errors): + ... # Don't bother validating the formset unless each form is valid on its own + ... return + ... titles = [] + ... for i in range(0, self.total_form_count()): + ... form = self.forms[i] + ... title = form.cleaned_data['title'] + ... if title in titles: + ... raise forms.ValidationError, "Articles in a set must have distinct titles." + ... titles.append(title) + + >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet) + >>> data = { + ... 'form-TOTAL_FORMS': u'2', + ... 'form-INITIAL_FORMS': u'0', + ... 'form-MAX_NUM_FORMS': u'', + ... 'form-0-title': u'Test', + ... 'form-0-pub_date': u'16 June 1904', + ... 'form-1-title': u'Test', + ... 'form-1-pub_date': u'23 June 1912', + ... } + >>> formset = ArticleFormSet(data) + >>> formset.is_valid() + False + >>> formset.errors + [{}, {}] + >>> formset.non_form_errors() + [u'Articles in a set must have distinct titles.'] + +The formset ``clean`` method is called after all the ``Form.clean`` methods +have been called. The errors will be found using the ``non_form_errors()`` +method on the formset. + +Dealing with ordering and deletion of forms +------------------------------------------- + +Common use cases with a formset is dealing with ordering and deletion of the +form instances. This has been dealt with for you. The ``formset_factory`` +provides two optional parameters ``can_order`` and ``can_delete`` that will do +the extra work of adding the extra fields and providing simpler ways of +getting to that data. + +``can_order`` +~~~~~~~~~~~~~ + +Default: ``False`` + +Lets create a formset with the ability to order:: + + >>> ArticleFormSet = formset_factory(ArticleForm, can_order=True) + >>> formset = ArticleFormSet(initial=[ + ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, + ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)}, + ... ]) + >>> for form in formset.forms: + ... print form.as_table() + <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" 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" value="2008-05-10" id="id_form-0-pub_date" /></td></tr> + <tr><th><label for="id_form-0-ORDER">Order:</label></th><td><input type="text" name="form-0-ORDER" value="1" id="id_form-0-ORDER" /></td></tr> + <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr> + <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr> + <tr><th><label for="id_form-1-ORDER">Order:</label></th><td><input type="text" name="form-1-ORDER" value="2" id="id_form-1-ORDER" /></td></tr> + <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr> + <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr> + <tr><th><label for="id_form-2-ORDER">Order:</label></th><td><input type="text" name="form-2-ORDER" id="id_form-2-ORDER" /></td></tr> + +This adds an additional field to each form. This new field is named ``ORDER`` +and is an ``forms.IntegerField``. For the forms that came from the initial +data it automatically assigned them a numeric value. Lets look at what will +happen when the user changes these values:: + + >>> data = { + ... 'form-TOTAL_FORMS': u'3', + ... 'form-INITIAL_FORMS': u'2', + ... 'form-MAX_NUM_FORMS': u'', + ... 'form-0-title': u'Article #1', + ... 'form-0-pub_date': u'2008-05-10', + ... 'form-0-ORDER': u'2', + ... 'form-1-title': u'Article #2', + ... 'form-1-pub_date': u'2008-05-11', + ... 'form-1-ORDER': u'1', + ... 'form-2-title': u'Article #3', + ... 'form-2-pub_date': u'2008-05-01', + ... 'form-2-ORDER': u'0', + ... } + + >>> formset = ArticleFormSet(data, initial=[ + ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, + ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)}, + ... ]) + >>> formset.is_valid() + True + >>> for form in formset.ordered_forms: + ... print form.cleaned_data + {'pub_date': datetime.date(2008, 5, 1), 'ORDER': 0, 'title': u'Article #3'} + {'pub_date': datetime.date(2008, 5, 11), 'ORDER': 1, 'title': u'Article #2'} + {'pub_date': datetime.date(2008, 5, 10), 'ORDER': 2, 'title': u'Article #1'} + +``can_delete`` +~~~~~~~~~~~~~~ + +Default: ``False`` + +Lets create a formset with the ability to delete:: + + >>> ArticleFormSet = formset_factory(ArticleForm, can_delete=True) + >>> formset = ArticleFormSet(initial=[ + ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, + ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)}, + ... ]) + >>> for form in formset.forms: + .... print form.as_table() + <input type="hidden" name="form-TOTAL_FORMS" value="3" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="2" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" /> + <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" 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" value="2008-05-10" id="id_form-0-pub_date" /></td></tr> + <tr><th><label for="id_form-0-DELETE">Delete:</label></th><td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" /></td></tr> + <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr> + <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr> + <tr><th><label for="id_form-1-DELETE">Delete:</label></th><td><input type="checkbox" name="form-1-DELETE" id="id_form-1-DELETE" /></td></tr> + <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr> + <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr> + <tr><th><label for="id_form-2-DELETE">Delete:</label></th><td><input type="checkbox" name="form-2-DELETE" id="id_form-2-DELETE" /></td></tr> + +Similar to ``can_order`` this adds a new field to each form named ``DELETE`` +and is a ``forms.BooleanField``. When data comes through marking any of the +delete fields you can access them with ``deleted_forms``:: + + >>> data = { + ... 'form-TOTAL_FORMS': u'3', + ... 'form-INITIAL_FORMS': u'2', + ... 'form-MAX_NUM_FORMS': u'', + ... 'form-0-title': u'Article #1', + ... 'form-0-pub_date': u'2008-05-10', + ... 'form-0-DELETE': u'on', + ... 'form-1-title': u'Article #2', + ... 'form-1-pub_date': u'2008-05-11', + ... 'form-1-DELETE': u'', + ... 'form-2-title': u'', + ... 'form-2-pub_date': u'', + ... 'form-2-DELETE': u'', + ... } + + >>> formset = ArticleFormSet(data, initial=[ + ... {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)}, + ... {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)}, + ... ]) + >>> [form.cleaned_data for form in formset.deleted_forms] + [{'DELETE': True, 'pub_date': datetime.date(2008, 5, 10), 'title': u'Article #1'}] + +Adding additional fields to a formset +------------------------------------- + +If you need to add additional fields to the formset this can be easily +accomplished. The formset base class provides an ``add_fields`` method. You +can simply override this method to add your own fields or even redefine the +default fields/attributes of the order and deletion fields:: + + >>> class BaseArticleFormSet(BaseFormSet): + ... def add_fields(self, form, index): + ... super(BaseArticleFormSet, self).add_fields(form, index) + ... form.fields["my_field"] = forms.CharField() + + >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet) + >>> formset = ArticleFormSet() + >>> for form in formset.forms: + ... print form.as_table() + <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> + <tr><th><label for="id_form-0-my_field">My field:</label></th><td><input type="text" name="form-0-my_field" id="id_form-0-my_field" /></td></tr> + +Using a formset in views and templates +-------------------------------------- + +Using a formset inside a view is as easy as using a regular ``Form`` class. +The only thing you will want to be aware of is making sure to use the +management form inside the template. Let's look at a sample view: + +.. code-block:: python + + def manage_articles(request): + ArticleFormSet = formset_factory(ArticleForm) + if request.method == 'POST': + formset = ArticleFormSet(request.POST, request.FILES) + if formset.is_valid(): + # do something with the formset.cleaned_data + pass + else: + formset = ArticleFormSet() + return render_to_response('manage_articles.html', {'formset': formset}) + +The ``manage_articles.html`` template might look like this: + +.. code-block:: html+django + + <form method="post" action=""> + {{ formset.management_form }} + <table> + {% for form in formset.forms %} + {{ form }} + {% endfor %} + </table> + </form> + +However the above can be slightly shortcutted and let the formset itself deal +with the management form: + +.. code-block:: html+django + + <form method="post" action=""> + <table> + {{ formset }} + </table> + </form> + +The above ends up calling the ``as_table`` method on the formset class. + +Using more than one formset in a view +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You are able to use more than one formset in a view if you like. Formsets +borrow much of its behavior from forms. With that said you are able to use +``prefix`` to prefix formset form field names with a given value to allow +more than one formset to be sent to a view without name clashing. Lets take +a look at how this might be accomplished: + +.. code-block:: python + + def manage_articles(request): + ArticleFormSet = formset_factory(ArticleForm) + BookFormSet = formset_factory(BookForm) + if request.method == 'POST': + article_formset = ArticleFormSet(request.POST, request.FILES, prefix='articles') + book_formset = BookFormSet(request.POST, request.FILES, prefix='books') + if article_formset.is_valid() and book_formset.is_valid(): + # do something with the cleaned_data on the formsets. + pass + else: + article_formset = ArticleFormSet(prefix='articles') + book_formset = BookFormSet(prefix='books') + return render_to_response('manage_articles.html', { + 'article_formset': article_formset, + 'book_formset': book_formset, + }) + +You would then render the formsets as normal. It is important to point out +that you need to pass ``prefix`` on both the POST and non-POST cases so that +it is rendered and processed correctly. diff --git a/parts/django/docs/topics/forms/index.txt b/parts/django/docs/topics/forms/index.txt new file mode 100644 index 0000000..30b09c0 --- /dev/null +++ b/parts/django/docs/topics/forms/index.txt @@ -0,0 +1,402 @@ +================== +Working with forms +================== + +.. admonition:: About this document + + This document provides an introduction to Django's form handling features. + For a more detailed look at specific areas of the forms API, see + :doc:`/ref/forms/api`, :doc:`/ref/forms/fields`, and + :doc:`/ref/forms/validation`. + +.. highlightlang:: html+django + +``django.forms`` is Django's form-handling library. + +While it is possible to process form submissions just using Django's +:class:`~django.http.HttpRequest` class, using the form library takes care of a +number of common form-related tasks. Using it, you can: + + 1. Display an HTML form with automatically generated form widgets. + 2. Check submitted data against a set of validation rules. + 3. Redisplay a form in the case of validation errors. + 4. Convert submitted form data to the relevant Python data types. + +Overview +======== + +The library deals with these concepts: + +.. glossary:: + + Widget + A class that corresponds to an HTML form widget, e.g. + ``<input type="text">`` or ``<textarea>``. This handles rendering of the + widget as HTML. + + Field + A class that is responsible for doing validation, e.g. + an ``EmailField`` that makes sure its data is a valid e-mail address. + + Form + A collection of fields that knows how to validate itself and + display itself as HTML. + + Form Media + The CSS and JavaScript resources that are required to render a form. + +The library is decoupled from the other Django components, such as the database +layer, views and templates. It relies only on Django settings, a couple of +``django.utils`` helper functions and Django's internationalization hooks (but +you're not required to be using internationalization features to use this +library). + +Form objects +============ + +A Form object encapsulates a sequence of form fields and a collection of +validation rules that must be fulfilled in order for the form to be accepted. +Form classes are created as subclasses of ``django.forms.Form`` and +make use of a declarative style that you'll be familiar with if you've used +Django's database models. + +For example, consider a form used to implement "contact me" functionality on a +personal Web site: + +.. code-block:: python + + from django import forms + + class ContactForm(forms.Form): + subject = forms.CharField(max_length=100) + message = forms.CharField() + sender = forms.EmailField() + cc_myself = forms.BooleanField(required=False) + +A form is composed of ``Field`` objects. In this case, our form has four +fields: ``subject``, ``message``, ``sender`` and ``cc_myself``. ``CharField``, +``EmailField`` and ``BooleanField`` are just three of the available field types; +a full list can be found in :doc:`/ref/forms/fields`. + +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 +---------------------- + +The standard pattern for processing a form in a view looks like this: + +.. code-block:: python + + def contact(request): + if request.method == 'POST': # If the form has been submitted... + form = ContactForm(request.POST) # A form bound to the POST data + if form.is_valid(): # All validation rules pass + # Process the data in form.cleaned_data + # ... + return HttpResponseRedirect('/thanks/') # Redirect after POST + else: + form = ContactForm() # An unbound form + + return render_to_response('contact.html', { + 'form': form, + }) + + +There are three 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. + +.. versionchanged:: 1.0 + The ``cleaned_data`` attribute was called ``clean_data`` in earlier releases. + +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. + +See :ref:`ref-forms-api-bound-unbound` for further information on the +differences between bound and unbound forms. + +Handling file uploads with a form +--------------------------------- + +To see how to handle file uploads with your form see +:ref:`binding-uploaded-files` for more information. + +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. + +Extending the above example, here's how the form data could be processed: + +.. code-block:: python + + if form.is_valid(): + subject = form.cleaned_data['subject'] + message = form.cleaned_data['message'] + sender = form.cleaned_data['sender'] + cc_myself = form.cleaned_data['cc_myself'] + + recipients = ['info@example.com'] + if cc_myself: + recipients.append(sender) + + from django.core.mail import send_mail + send_mail(subject, message, sender, recipients) + return HttpResponseRedirect('/thanks/') # Redirect after POST + +For more on sending e-mail from Django, see :doc:`/topics/email`. + +Displaying a form using a template +---------------------------------- + +Forms are designed to work with the Django template language. In the above +example, we passed our ``ContactForm`` instance to the template using the +context variable ``form``. Here's a simple example template:: + + <form action="/contact/" method="post"> + {{ form.as_p }} + <input type="submit" value="Submit" /> + </form> + +The form only outputs its own fields; it is up to you to provide the surrounding +``<form>`` tags and the submit button. + +``form.as_p`` will output the form with each form field and accompanying label +wrapped in a paragraph. Here's the output for our example template:: + + <form action="/contact/" method="post"> + <p><label for="id_subject">Subject:</label> + <input id="id_subject" type="text" name="subject" maxlength="100" /></p> + <p><label for="id_message">Message:</label> + <input type="text" name="message" id="id_message" /></p> + <p><label for="id_sender">Sender:</label> + <input type="text" name="sender" id="id_sender" /></p> + <p><label for="id_cc_myself">Cc myself:</label> + <input type="checkbox" name="cc_myself" id="id_cc_myself" /></p> + <input type="submit" value="Submit" /> + </form> + +Note that each form field has an ID attribute set to ``id_<field-name>``, which +is referenced by the accompanying label tag. This is important for ensuring +forms are accessible to assistive technology such as screen reader software. You +can also :ref:`customize the way in which labels and ids are generated +<ref-forms-api-configuring-label>`. + +You can also use ``form.as_table`` to output table rows (you'll need to provide +your own ``<table>`` tags) and ``form.as_ul`` to output list items. + +Customizing the form template +----------------------------- + +If the default generated HTML is not to your taste, you can completely customize +the way a form is presented using the Django template language. Extending the +above example:: + + <form action="/contact/" method="post"> + {{ form.non_field_errors }} + <div class="fieldWrapper"> + {{ form.subject.errors }} + <label for="id_subject">E-mail subject:</label> + {{ form.subject }} + </div> + <div class="fieldWrapper"> + {{ form.message.errors }} + <label for="id_message">Your message:</label> + {{ form.message }} + </div> + <div class="fieldWrapper"> + {{ form.sender.errors }} + <label for="id_sender">Your email address:</label> + {{ form.sender }} + </div> + <div class="fieldWrapper"> + {{ form.cc_myself.errors }} + <label for="id_cc_myself">CC yourself?</label> + {{ form.cc_myself }} + </div> + <p><input type="submit" value="Send message" /></p> + </form> + +Each named form-field can be output to the template using +``{{ form.name_of_field }}``, which will produce the HTML needed to display the +form widget. Using ``{{ form.name_of_field.errors }}`` displays a list of form +errors, rendered as an unordered list. This might look like:: + + <ul class="errorlist"> + <li>Sender is required.</li> + </ul> + +The list has a CSS class of ``errorlist`` to allow you to style its appearance. +If you wish to further customize the display of errors you can do so by looping +over them:: + + {% if form.subject.errors %} + <ol> + {% for error in form.subject.errors %} + <li><strong>{{ error|escape }}</strong></li> + {% endfor %} + </ol> + {% endif %} + +Looping over the form's fields +------------------------------ + +If you're using the same HTML for each of your form fields, you can reduce +duplicate code by looping through each field in turn using a ``{% for %}`` +loop:: + + <form action="/contact/" method="post"> + {% for field in form %} + <div class="fieldWrapper"> + {{ field.errors }} + {{ field.label_tag }}: {{ field }} + </div> + {% endfor %} + <p><input type="submit" value="Send message" /></p> + </form> + +Within this loop, ``{{ field }}`` is an instance of :class:`BoundField`. +``BoundField`` also has the following attributes, which can be useful in your +templates: + + ``{{ field.label }}`` + The label of the field, e.g. ``E-mail address``. + + ``{{ field.label_tag }}`` + The field's label wrapped in the appropriate HTML ``<label>`` tag, + e.g. ``<label for="id_email">E-mail address</label>`` + + ``{{ field.html_name }}`` + The name of the field that will be used in the input element's name + field. This takes the form prefix into account, if it has been set. + + ``{{ field.help_text }}`` + Any help text that has been associated with the field. + + ``{{ field.errors }}`` + Outputs a ``<ul class="errorlist">`` containing any validation errors + corresponding to this field. You can customize the presentation of + the errors with a ``{% for error in field.errors %}`` loop. In this + case, each object in the loop is a simple string containing the error + message. + + ``field.is_hidden`` + This attribute is ``True`` if the form field is a hidden field and + ``False`` otherwise. It's not particularly useful as a template + variable, but could be useful in conditional tests such as:: + + {% if field.is_hidden %} + {# Do something special #} + {% endif %} + +Looping over hidden and visible fields +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you're manually laying out a form in a template, as opposed to relying on +Django's default form layout, you might want to treat ``<input type="hidden">`` +fields differently than non-hidden fields. For example, because hidden fields +don't display anything, putting error messages "next to" the field could cause +confusion for your users -- so errors for those fields should be handled +differently. + +Django provides two methods on a form that allow you to loop over the hidden +and visible fields independently: ``hidden_fields()`` and +``visible_fields()``. Here's a modification of an earlier example that uses +these two methods:: + + <form action="/contact/" method="post"> + {% for field in form.visible_fields %} + <div class="fieldWrapper"> + + {# Include the hidden fields in the form #} + {% if forloop.first %} + {% for hidden in form.hidden_fields %} + {{ hidden }} + {% endfor %} + {% endif %} + + {{ field.errors }} + {{ field.label_tag }}: {{ field }} + </div> + {% endfor %} + <p><input type="submit" value="Send message" /></p> + </form> + +This example does not handle any errors in the hidden fields. Usually, an +error in a hidden field is a sign of form tampering, since normal form +interaction won't alter them. However, you could easily insert some error +displays for those form errors, as well. + +.. versionadded:: 1.1 + The ``hidden_fields`` and ``visible_fields`` methods are new in Django + 1.1. + +Reusable form templates +----------------------- + +If your site uses the same rendering logic for forms in multiple places, you +can reduce duplication by saving the form's loop in a standalone template and +using the :ttag:`include` tag to reuse it in other templates:: + + <form action="/contact/" method="post"> + {% include "form_snippet.html" %} + <p><input type="submit" value="Send message" /></p> + </form> + + # In form_snippet.html: + + {% for field in form %} + <div class="fieldWrapper"> + {{ field.errors }} + {{ field.label_tag }}: {{ field }} + </div> + {% endfor %} + +If the form object passed to a template has a different name within the +context, you can alias it using the :ttag:`with` tag:: + + <form action="/comments/add/" method="post"> + {% with comment_form as form %} + {% include "form_snippet.html" %} + {% endwith %} + <p><input type="submit" value="Submit comment" /></p> + </form> + +If you find yourself doing this often, you might consider creating a custom +:ref:`inclusion tag<howto-custom-template-tags-inclusion-tags>`. + +Further topics +============== + +This covers the basics, but forms can do a whole lot more: + +.. toctree:: + :maxdepth: 2 + + modelforms + formsets + media + +.. seealso:: + + :doc:`The Forms Reference </ref/forms/index>` + Covers the full API reference, including form fields, form widgets, + and form and field validation. diff --git a/parts/django/docs/topics/forms/media.txt b/parts/django/docs/topics/forms/media.txt new file mode 100644 index 0000000..fe70894 --- /dev/null +++ b/parts/django/docs/topics/forms/media.txt @@ -0,0 +1,309 @@ +Form Media +========== + +Rendering an attractive and easy-to-use Web form requires more than just +HTML - it also requires CSS stylesheets, and if you want to use fancy +"Web2.0" widgets, you may also need to include some JavaScript on each +page. The exact combination of CSS and JavaScript that is required for +any given page will depend upon the widgets that are in use on that page. + +This is where Django media definitions come in. Django allows you to +associate different media files with the forms and widgets that require +that media. For example, if you want to use a calendar to render DateFields, +you can define a custom Calendar widget. This widget can then be associated +with the CSS and JavaScript that is required to render the calendar. When +the Calendar widget is used on a form, Django is able to identify the CSS and +JavaScript files that are required, and provide the list of file names +in a form suitable for easy inclusion on your Web page. + +.. admonition:: Media and Django Admin + + The Django Admin application defines a number of customized widgets + for calendars, filtered selections, and so on. These widgets define + media requirements, and the Django Admin uses the custom widgets + in place of the Django defaults. The Admin templates will only include + those media files that are required to render the widgets on any + given page. + + If you like the widgets that the Django Admin application uses, + feel free to use them in your own application! They're all stored + in ``django.contrib.admin.widgets``. + +.. admonition:: Which JavaScript toolkit? + + Many JavaScript toolkits exist, and many of them include widgets (such + as calendar widgets) that can be used to enhance your application. + Django has deliberately avoided blessing any one JavaScript toolkit. + Each toolkit has its own relative strengths and weaknesses - use + whichever toolkit suits your requirements. Django is able to integrate + with any JavaScript toolkit. + +Media as a static definition +---------------------------- + +The easiest way to define media is as a static definition. Using this method, +the media declaration is an inner class. The properties of the inner class +define the media requirements. + +Here's a simple example:: + + class CalendarWidget(forms.TextInput): + class Media: + css = { + 'all': ('pretty.css',) + } + js = ('animations.js', 'actions.js') + +This code defines a ``CalendarWidget``, which will be based on ``TextInput``. +Every time the CalendarWidget is used on a form, that form will be directed +to include the CSS file ``pretty.css``, and the JavaScript files +``animations.js`` and ``actions.js``. + +This static media definition is converted at runtime into a widget property +named ``media``. The media for a CalendarWidget instance can be retrieved +through this property:: + + >>> w = CalendarWidget() + >>> print w.media + <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> + <script type="text/javascript" src="http://media.example.com/animations.js"></script> + <script type="text/javascript" src="http://media.example.com/actions.js"></script> + +Here's a list of all possible ``Media`` options. There are no required options. + +``css`` +~~~~~~~ + +A dictionary describing the CSS files required for various forms of output +media. + +The values in the dictionary should be a tuple/list of file names. See +`the section on media paths`_ for details of how to specify paths to media +files. + +.. _the section on media paths: `Paths in media definitions`_ + +The keys in the dictionary are the output media types. These are the same +types accepted by CSS files in media declarations: 'all', 'aural', 'braille', +'embossed', 'handheld', 'print', 'projection', 'screen', 'tty' and 'tv'. If +you need to have different stylesheets for different media types, provide +a list of CSS files for each output medium. The following example would +provide two CSS options -- one for the screen, and one for print:: + + class Media: + css = { + 'screen': ('pretty.css',), + 'print': ('newspaper.css',) + } + +If a group of CSS files are appropriate for multiple output media types, +the dictionary key can be a comma separated list of output media types. +In the following example, TV's and projectors will have the same media +requirements:: + + class Media: + css = { + 'screen': ('pretty.css',), + 'tv,projector': ('lo_res.css',), + 'print': ('newspaper.css',) + } + +If this last CSS definition were to be rendered, it would become the following HTML:: + + <link href="http://media.example.com/pretty.css" type="text/css" media="screen" rel="stylesheet" /> + <link href="http://media.example.com/lo_res.css" type="text/css" media="tv,projector" rel="stylesheet" /> + <link href="http://media.example.com/newspaper.css" type="text/css" media="print" rel="stylesheet" /> + +``js`` +~~~~~~ + +A tuple describing the required JavaScript files. See +`the section on media paths`_ for details of how to specify paths to media +files. + +``extend`` +~~~~~~~~~~ + +A boolean defining inheritance behavior for media declarations. + +By default, any object using a static media definition will inherit all the +media associated with the parent widget. This occurs regardless of how the +parent defines its media requirements. For example, if we were to extend our +basic Calendar widget from the example above:: + + >>> class FancyCalendarWidget(CalendarWidget): + ... class Media: + ... css = { + ... 'all': ('fancy.css',) + ... } + ... js = ('whizbang.js',) + + >>> w = FancyCalendarWidget() + >>> print w.media + <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> + <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" /> + <script type="text/javascript" src="http://media.example.com/animations.js"></script> + <script type="text/javascript" src="http://media.example.com/actions.js"></script> + <script type="text/javascript" src="http://media.example.com/whizbang.js"></script> + +The FancyCalendar widget inherits all the media from it's parent widget. If +you don't want media to be inherited in this way, add an ``extend=False`` +declaration to the media declaration:: + + >>> class FancyCalendarWidget(CalendarWidget): + ... class Media: + ... extend = False + ... css = { + ... 'all': ('fancy.css',) + ... } + ... js = ('whizbang.js',) + + >>> w = FancyCalendarWidget() + >>> print w.media + <link href="http://media.example.com/fancy.css" type="text/css" media="all" rel="stylesheet" /> + <script type="text/javascript" src="http://media.example.com/whizbang.js"></script> + +If you require even more control over media inheritance, define your media +using a `dynamic property`_. Dynamic properties give you complete control over +which media files are inherited, and which are not. + +.. _dynamic property: `Media as a dynamic property`_ + +Media as a dynamic property +--------------------------- + +If you need to perform some more sophisticated manipulation of media +requirements, you can define the media property directly. This is done +by defining a widget property that returns an instance of ``forms.Media``. +The constructor for ``forms.Media`` accepts ``css`` and ``js`` keyword +arguments in the same format as that used in a static media definition. + +For example, the static media definition for our Calendar Widget could +also be defined in a dynamic fashion:: + + class CalendarWidget(forms.TextInput): + def _media(self): + return forms.Media(css={'all': ('pretty.css',)}, + js=('animations.js', 'actions.js')) + media = property(_media) + +See the section on `Media objects`_ for more details on how to construct +return values for dynamic media properties. + +Paths in media definitions +-------------------------- + +Paths used to specify media can be either relative or absolute. If a path +starts with '/', 'http://' or 'https://', it will be interpreted as an absolute +path, and left as-is. All other paths will be prepended with the value of +``settings.MEDIA_URL``. For example, if the MEDIA_URL for your site was +``http://media.example.com/``:: + + class CalendarWidget(forms.TextInput): + class Media: + css = { + 'all': ('/css/pretty.css',), + } + js = ('animations.js', 'http://othersite.com/actions.js') + + >>> w = CalendarWidget() + >>> print w.media + <link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" /> + <script type="text/javascript" src="http://media.example.com/animations.js"></script> + <script type="text/javascript" src="http://othersite.com/actions.js"></script> + +Media objects +------------- + +When you interrogate the media attribute of a widget or form, the value that +is returned is a ``forms.Media`` object. As we have already seen, the string +representation of a Media object is the HTML required to include media +in the ``<head>`` block of your HTML page. + +However, Media objects have some other interesting properties. + +Media subsets +~~~~~~~~~~~~~ + +If you only want media of a particular type, you can use the subscript operator +to filter out a medium of interest. For example:: + + >>> w = CalendarWidget() + >>> print w.media + <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> + <script type="text/javascript" src="http://media.example.com/animations.js"></script> + <script type="text/javascript" src="http://media.example.com/actions.js"></script> + + >>> print w.media['css'] + <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> + +When you use the subscript operator, the value that is returned is a new +Media object -- but one that only contains the media of interest. + +Combining media objects +~~~~~~~~~~~~~~~~~~~~~~~ + +Media objects can also be added together. When two media objects are added, +the resulting Media object contains the union of the media from both files:: + + >>> class CalendarWidget(forms.TextInput): + ... class Media: + ... css = { + ... 'all': ('pretty.css',) + ... } + ... js = ('animations.js', 'actions.js') + + >>> class OtherWidget(forms.TextInput): + ... class Media: + ... js = ('whizbang.js',) + + >>> w1 = CalendarWidget() + >>> w2 = OtherWidget() + >>> print w1.media + w2.media + <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> + <script type="text/javascript" src="http://media.example.com/animations.js"></script> + <script type="text/javascript" src="http://media.example.com/actions.js"></script> + <script type="text/javascript" src="http://media.example.com/whizbang.js"></script> + +Media on Forms +-------------- + +Widgets aren't the only objects that can have media definitions -- forms +can also define media. The rules for media definitions on forms are the +same as the rules for widgets: declarations can be static or dynamic; +path and inheritance rules for those declarations are exactly the same. + +Regardless of whether you define a media declaration, *all* Form objects +have a media property. The default value for this property is the result +of adding the media definitions for all widgets that are part of the form:: + + >>> class ContactForm(forms.Form): + ... date = DateField(widget=CalendarWidget) + ... name = CharField(max_length=40, widget=OtherWidget) + + >>> f = ContactForm() + >>> f.media + <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> + <script type="text/javascript" src="http://media.example.com/animations.js"></script> + <script type="text/javascript" src="http://media.example.com/actions.js"></script> + <script type="text/javascript" src="http://media.example.com/whizbang.js"></script> + +If you want to associate additional media with a form -- for example, CSS for form +layout -- simply add a media declaration to the form:: + + >>> class ContactForm(forms.Form): + ... date = DateField(widget=CalendarWidget) + ... name = CharField(max_length=40, widget=OtherWidget) + ... + ... class Media: + ... css = { + ... 'all': ('layout.css',) + ... } + + >>> f = ContactForm() + >>> f.media + <link href="http://media.example.com/pretty.css" type="text/css" media="all" rel="stylesheet" /> + <link href="http://media.example.com/layout.css" type="text/css" media="all" rel="stylesheet" /> + <script type="text/javascript" src="http://media.example.com/animations.js"></script> + <script type="text/javascript" src="http://media.example.com/actions.js"></script> + <script type="text/javascript" src="http://media.example.com/whizbang.js"></script> diff --git a/parts/django/docs/topics/forms/modelforms.txt b/parts/django/docs/topics/forms/modelforms.txt new file mode 100644 index 0000000..23ed9a7 --- /dev/null +++ b/parts/django/docs/topics/forms/modelforms.txt @@ -0,0 +1,885 @@ +========================== +Creating forms from models +========================== + +.. module:: django.forms.models + :synopsis: ModelForm and ModelFormset. + +.. currentmodule:: django.forms + +``ModelForm`` +============= +.. class:: ModelForm + +If you're building a database-driven app, chances are you'll have forms that +map closely to Django models. For instance, you might have a ``BlogComment`` +model, and you want to create a form that lets people submit comments. In this +case, it would be redundant to define the field types in your form, because +you've already defined the fields in your model. + +For this reason, Django provides a helper class that let you create a ``Form`` +class from a Django model. + +For example:: + + >>> from django.forms import ModelForm + + # Create the form class. + >>> class ArticleForm(ModelForm): + ... class Meta: + ... model = Article + + # Creating a form to add an article. + >>> form = ArticleForm() + + # Creating a form to change an existing article. + >>> article = Article.objects.get(pk=1) + >>> form = ArticleForm(instance=article) + +Field types +----------- + +The generated ``Form`` class will have a form field for every model field. Each +model field has a corresponding default form field. For example, a +``CharField`` on a model is represented as a ``CharField`` on a form. A +model ``ManyToManyField`` is represented as a ``MultipleChoiceField``. Here is +the full list of conversions: + + =============================== ======================================== + Model field Form field + =============================== ======================================== + ``AutoField`` Not represented in the form + + ``BigIntegerField`` ``IntegerField`` with ``min_value`` set + to -9223372036854775808 and ``max_value`` + set to 9223372036854775807. + + ``BooleanField`` ``BooleanField`` + + ``CharField`` ``CharField`` with ``max_length`` set to + the model field's ``max_length`` + + ``CommaSeparatedIntegerField`` ``CharField`` + + ``DateField`` ``DateField`` + + ``DateTimeField`` ``DateTimeField`` + + ``DecimalField`` ``DecimalField`` + + ``EmailField`` ``EmailField`` + + ``FileField`` ``FileField`` + + ``FilePathField`` ``CharField`` + + ``FloatField`` ``FloatField`` + + ``ForeignKey`` ``ModelChoiceField`` (see below) + + ``ImageField`` ``ImageField`` + + ``IntegerField`` ``IntegerField`` + + ``IPAddressField`` ``IPAddressField`` + + ``ManyToManyField`` ``ModelMultipleChoiceField`` (see + below) + + ``NullBooleanField`` ``CharField`` + + ``PhoneNumberField`` ``USPhoneNumberField`` + (from ``django.contrib.localflavor.us``) + + ``PositiveIntegerField`` ``IntegerField`` + + ``PositiveSmallIntegerField`` ``IntegerField`` + + ``SlugField`` ``SlugField`` + + ``SmallIntegerField`` ``IntegerField`` + + ``TextField`` ``CharField`` with + ``widget=forms.Textarea`` + + ``TimeField`` ``TimeField`` + + ``URLField`` ``URLField`` with ``verify_exists`` set + to the model field's ``verify_exists`` + + ``XMLField`` ``CharField`` with + ``widget=forms.Textarea`` + =============================== ======================================== + + +.. versionadded:: 1.0 + The ``FloatField`` form field and ``DecimalField`` model and form fields + are new in Django 1.0. + +.. 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: + + * ``ForeignKey`` is represented by ``django.forms.ModelChoiceField``, + which is a ``ChoiceField`` whose choices are a model ``QuerySet``. + + * ``ManyToManyField`` is represented by + ``django.forms.ModelMultipleChoiceField``, which is a + ``MultipleChoiceField`` whose choices are a model ``QuerySet``. + +In addition, each generated form field has attributes set as follows: + + * If the model field has ``blank=True``, then ``required`` is set to + ``False`` on the form field. Otherwise, ``required=True``. + + * The form field's ``label`` is set to the ``verbose_name`` of the model + field, with the first character capitalized. + + * The form field's ``help_text`` is set to the ``help_text`` of the model + field. + + * If the model field has ``choices`` set, then the form field's ``widget`` + will be set to ``Select``, with choices coming from the model field's + ``choices``. The choices will normally include the blank choice which is + selected by default. If the field is required, this forces the user to + make a selection. The blank choice will not be included if the model + field has ``blank=False`` and an explicit ``default`` value (the + ``default`` value will be initially selected instead). + +Finally, note that you can override the form field used for a given model +field. See `Overriding the default field types or widgets`_ below. + +A full example +-------------- + +Consider this set of models:: + + from django.db import models + from django.forms import ModelForm + + TITLE_CHOICES = ( + ('MR', 'Mr.'), + ('MRS', 'Mrs.'), + ('MS', 'Ms.'), + ) + + class Author(models.Model): + name = models.CharField(max_length=100) + title = models.CharField(max_length=3, choices=TITLE_CHOICES) + birth_date = models.DateField(blank=True, null=True) + + def __unicode__(self): + return self.name + + class Book(models.Model): + name = models.CharField(max_length=100) + authors = models.ManyToManyField(Author) + + class AuthorForm(ModelForm): + class Meta: + model = Author + + class BookForm(ModelForm): + class Meta: + model = Book + +With these models, the ``ModelForm`` subclasses above would be roughly +equivalent to this (the only difference being the ``save()`` method, which +we'll discuss in a moment.):: + + class AuthorForm(forms.Form): + name = forms.CharField(max_length=100) + title = forms.CharField(max_length=3, + widget=forms.Select(choices=TITLE_CHOICES)) + birth_date = forms.DateField(required=False) + + class BookForm(forms.Form): + name = forms.CharField(max_length=100) + authors = forms.ModelMultipleChoiceField(queryset=Author.objects.all()) + +The ``is_valid()`` method and ``errors`` +---------------------------------------- + +.. versionchanged:: 1.2 + +The first time you call ``is_valid()`` or access the ``errors`` attribute of a +``ModelForm`` has always triggered form validation, but as of Django 1.2, it +will also trigger :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 +--------------------- + +Every form produced by ``ModelForm`` also has a ``save()`` +method. This method creates and saves a database object from the data +bound to the form. A subclass of ``ModelForm`` can accept an existing +model instance as the keyword argument ``instance``; if this is +supplied, ``save()`` will update that instance. If it's not supplied, +``save()`` will create a new instance of the specified model:: + + # Create a form instance from POST data. + >>> f = ArticleForm(request.POST) + + # Save a new Article object from the form's data. + >>> new_article = f.save() + + # Create a form to edit an existing Article. + >>> a = Article.objects.get(pk=1) + >>> f = ArticleForm(instance=a) + >>> f.save() + + # Create a form to edit an existing Article, but use + # POST data to populate the form. + >>> a = Article.objects.get(pk=1) + >>> f = ArticleForm(request.POST, instance=a) + >>> f.save() + +Note that ``save()`` will raise a ``ValueError`` if the data in the form +doesn't validate -- i.e., if form.errors evaluates to True. + +This ``save()`` method accepts an optional ``commit`` keyword argument, which +accepts either ``True`` or ``False``. If you call ``save()`` with +``commit=False``, then it will return an object that hasn't yet been saved to +the database. In this case, it's up to you to call ``save()`` on the resulting +model instance. This is useful if you want to do custom processing on the +object before saving it, or if you want to use one of the specialized +:ref:`model saving options <ref-models-force-insert>`. ``commit`` is ``True`` +by default. + +Another side effect of using ``commit=False`` is seen when your model has +a many-to-many relation with another model. If your model has a many-to-many +relation and you specify ``commit=False`` when you save a form, Django cannot +immediately save the form data for the many-to-many relation. This is because +it isn't possible to save many-to-many data for an instance until the instance +exists in the database. + +To work around this problem, every time you save a form using ``commit=False``, +Django adds a ``save_m2m()`` method to your ``ModelForm`` subclass. After +you've manually saved the instance produced by the form, you can invoke +``save_m2m()`` to save the many-to-many form data. For example:: + + # Create a form instance with POST data. + >>> f = AuthorForm(request.POST) + + # Create, but don't save the new author instance. + >>> new_author = f.save(commit=False) + + # Modify the author in some way. + >>> new_author.some_field = 'some_value' + + # Save the new instance. + >>> new_author.save() + + # Now, save the many-to-many data for the form. + >>> f.save_m2m() + +Calling ``save_m2m()`` is only required if you use ``save(commit=False)``. +When you use a simple ``save()`` on a form, all data -- including +many-to-many data -- is saved without the need for any additional method calls. +For example:: + + # Create a form instance with POST data. + >>> a = Author() + >>> f = AuthorForm(request.POST, instance=a) + + # Create and save the new author instance. There's no need to do anything else. + >>> new_author = f.save() + +Other than the ``save()`` and ``save_m2m()`` methods, a ``ModelForm`` works +exactly the same way as any other ``forms`` form. For example, the +``is_valid()`` method is used to check for validity, the ``is_multipart()`` +method is used to determine whether a form requires multipart file upload (and +hence whether ``request.FILES`` must be passed to the form), etc. See +:ref:`binding-uploaded-files` for more information. + +Using a subset of fields on the form +------------------------------------ + +In some cases, you may not want all the model fields to appear on the generated +form. There are three ways of telling ``ModelForm`` to use only a subset of the +model fields: + +1. Set ``editable=False`` on the model field. As a result, *any* form + created from the model via ``ModelForm`` will not include that + field. + +2. Use the ``fields`` attribute of the ``ModelForm``'s inner ``Meta`` + class. This attribute, if given, should be a list of field names + to include in the form. + + .. versionchanged:: 1.1 + + The form will render the fields in the same order they are specified in the + ``fields`` attribute. + +3. Use the ``exclude`` attribute of the ``ModelForm``'s inner ``Meta`` + class. This attribute, if given, should be a list of field names + to exclude from the form. + +For example, if you want a form for the ``Author`` model (defined +above) that includes only the ``name`` and ``title`` fields, you would +specify ``fields`` or ``exclude`` like this:: + + class PartialAuthorForm(ModelForm): + class Meta: + model = Author + fields = ('name', 'title') + + class PartialAuthorForm(ModelForm): + class Meta: + model = Author + exclude = ('birth_date',) + +Since the Author model has only 3 fields, 'name', 'title', and +'birth_date', the forms above will contain exactly the same fields. + +.. note:: + + If you specify ``fields`` or ``exclude`` when creating a form with + ``ModelForm``, then the fields that are not in the resulting form will not + be set by the form's ``save()`` method. Django will prevent any attempt to + save an incomplete model, so if the model does not allow the missing fields + to be empty, and does not provide a default value for the missing fields, + any attempt to ``save()`` a ``ModelForm`` with missing fields will fail. + To avoid this failure, you must instantiate your model with initial values + for the missing, but required fields:: + + author = Author(title='Mr') + form = PartialAuthorForm(request.POST, instance=author) + form.save() + + Alternatively, you can use ``save(commit=False)`` and manually set + any extra required fields:: + + form = PartialAuthorForm(request.POST) + author = form.save(commit=False) + author.title = 'Mr' + author.save() + + See the `section on saving forms`_ for more details on using + ``save(commit=False)``. + +.. _section on saving forms: `The save() method`_ + +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 +``ModelForm`` gives you the flexibility of changing the form field type and +widget for a given model field. + +To specify a custom widget for a field, use the ``widgets`` attribute of the +inner ``Meta`` class. This should be a dictionary mapping field names to widget +classes or instances. + +For example, if you want the a ``CharField`` for the ``name`` +attribute of ``Author`` to be represented by a ``<textarea>`` instead +of its default ``<input type="text">``, you can override the field's +widget:: + + from django.forms import ModelForm, Textarea + + class AuthorForm(ModelForm): + class Meta: + model = Author + fields = ('name', 'title', 'birth_date') + widgets = { + 'name': Textarea(attrs={'cols': 80, 'rows': 20}), + } + +The ``widgets`` dictionary accepts either widget instances (e.g., +``Textarea(...)``) or classes (e.g., ``Textarea``). + +If you want to further customize a field -- including its type, label, etc. -- +you can do this by declaratively specifying fields like you would in a regular +``Form``. Declared fields will override the default ones generated by using the +``model`` attribute. + +For example, if you wanted to use ``MyDateFormField`` for the ``pub_date`` +field, you could do the following:: + + class ArticleForm(ModelForm): + pub_date = MyDateFormField() + + class Meta: + model = Article + +If you want to override a field's default label, then specify the ``label`` +parameter when declaring the form field:: + + >>> class ArticleForm(ModelForm): + ... pub_date = DateField(label='Publication date') + ... + ... class Meta: + ... model = Article + +.. note:: + + If you explicitly instantiate a form field like this, Django assumes that you + want to completely define its behavior; therefore, default attributes (such as + ``max_length`` or ``required``) are not drawn from the corresponding model. If + you want to maintain the behavior specified in the model, you must set the + relevant arguments explicitly when declaring the form field. + + For example, if the ``Article`` model looks like this:: + + class Article(models.Model): + headline = models.CharField(max_length=200, null=True, blank=True, + help_text="Use puns liberally") + content = models.TextField() + + and you want to do some custom validation for ``headline``, while keeping + the ``blank`` and ``help_text`` values as specified, you might define + ``ArticleForm`` like this:: + + class ArticleForm(ModelForm): + headline = MyFormField(max_length=200, required=False, + help_text="Use puns liberally") + + class Meta: + model = Article + + See the :doc:`form field documentation </ref/forms/fields>` for more information + on fields and their arguments. + +Changing the order of fields +---------------------------- + +.. versionadded:: 1.1 + +By default, a ``ModelForm`` will render fields in the same order that they are +defined on the model, with ``ManyToManyField`` instances appearing last. If +you want to change the order in which fields are rendered, you can use the +``fields`` attribute on the ``Meta`` class. + +The ``fields`` attribute defines the subset of model fields that will be +rendered, and the order in which they will be rendered. For example given this +model:: + + class Book(models.Model): + author = models.ForeignKey(Author) + title = models.CharField(max_length=100) + +the ``author`` field would be rendered first. If we wanted the title field +to be rendered first, we could specify the following ``ModelForm``:: + + >>> class BookForm(ModelForm): + ... class Meta: + ... model = Book + ... fields = ('title', 'author') + +.. _overriding-modelform-clean-method: + +Overriding the clean() method +----------------------------- + +You can override the ``clean()`` method on a model form to provide additional +validation in the same way you can on a normal form. + +In this regard, model forms have two specific characteristics when compared to +forms: + +By default the ``clean()`` method validates the uniqueness of fields that are +marked as ``unique``, ``unique_together`` or ``unique_for_date|month|year`` on +the model. Therefore, if you would like to override the ``clean()`` method and +maintain the default validation, you must call the parent class's ``clean()`` +method. + +Also, a model form instance bound to a model object will contain a +``self.instance`` attribute that gives model form methods access to that +specific model instance. + +Form inheritance +---------------- + +As with basic forms, you can extend and reuse ``ModelForms`` by inheriting +them. This is useful if you need to declare extra fields or extra methods on a +parent class for use in a number of forms derived from models. For example, +using the previous ``ArticleForm`` class:: + + >>> class EnhancedArticleForm(ArticleForm): + ... def clean_pub_date(self): + ... ... + +This creates a form that behaves identically to ``ArticleForm``, except there's +some extra validation and cleaning for the ``pub_date`` field. + +You can also subclass the parent's ``Meta`` inner class if you want to change +the ``Meta.fields`` or ``Meta.excludes`` lists:: + + >>> class RestrictedArticleForm(EnhancedArticleForm): + ... class Meta(ArticleForm.Meta): + ... exclude = ('body',) + +This adds the extra method from the ``EnhancedArticleForm`` and modifies +the original ``ArticleForm.Meta`` to remove one field. + +There are a couple of things to note, however. + + * Normal Python name resolution rules apply. If you have multiple base + classes that declare a ``Meta`` inner class, only the first one will be + used. This means the child's ``Meta``, if it exists, otherwise the + ``Meta`` of the first parent, etc. + + * For technical reasons, a subclass cannot inherit from both a ``ModelForm`` + and a ``Form`` simultaneously. + +Chances are these notes won't affect you unless you're trying to do something +tricky with subclassing. + +Interaction with model validation +--------------------------------- + +As part of its validation process, ``ModelForm`` will call the ``clean()`` +method of each field on your model that has a corresponding field on your form. +If you have excluded any model fields, validation will not be run on those +fields. See the :doc:`form validation </ref/forms/validation>` documentation +for more on how field cleaning and validation work. Also, your model's +``clean()`` method will be called before any uniqueness checks are made. See +:ref:`Validating objects <validating-objects>` for more information on the +model's ``clean()`` hook. + +.. _model-formsets: + +Model formsets +============== + +Like :doc:`regular formsets </topics/forms/formsets>`, Django provides a couple +of enhanced formset classes that make it easy to work with Django models. Let's +reuse the ``Author`` model from above:: + + >>> from django.forms.models import modelformset_factory + >>> AuthorFormSet = modelformset_factory(Author) + +This will create a formset that is capable of working with the data associated +with the ``Author`` model. It works just like a regular formset:: + + >>> formset = AuthorFormSet() + >>> print formset + <input type="hidden" name="form-TOTAL_FORMS" value="1" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="0" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" /> + <tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" maxlength="100" /></td></tr> + <tr><th><label for="id_form-0-title">Title:</label></th><td><select name="form-0-title" id="id_form-0-title"> + <option value="" selected="selected">---------</option> + <option value="MR">Mr.</option> + <option value="MRS">Mrs.</option> + <option value="MS">Ms.</option> + </select></td></tr> + <tr><th><label for="id_form-0-birth_date">Birth date:</label></th><td><input type="text" name="form-0-birth_date" id="id_form-0-birth_date" /><input type="hidden" name="form-0-id" id="id_form-0-id" /></td></tr> + +.. note:: + ``modelformset_factory`` uses ``formset_factory`` to generate formsets. + This means that a model formset is just an extension of a basic formset + that knows how to interact with a particular model. + +Changing the queryset +--------------------- + +By default, when you create a formset from a model, the formset will use a +queryset that includes all objects in the model (e.g., +``Author.objects.all()``). You can override this behavior by using the +``queryset`` argument:: + + >>> formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O')) + +Alternatively, you can create a subclass that sets ``self.queryset`` in +``__init__``:: + + from django.forms.models import BaseModelFormSet + + class BaseAuthorFormSet(BaseModelFormSet): + def __init__(self, *args, **kwargs): + super(BaseAuthorFormSet, self).__init__(*args, **kwargs) + self.queryset = Author.objects.filter(name__startswith='O') + +Then, pass your ``BaseAuthorFormSet`` class to the factory function:: + + >>> AuthorFormSet = modelformset_factory(Author, formset=BaseAuthorFormSet) + +If you want to return a formset that doesn't include *any* pre-existing +instances of the model, you can specify an empty QuerySet:: + + >>> AuthorFormSet(queryset=Author.objects.none()) + + +Controlling which fields are used with ``fields`` and ``exclude`` +----------------------------------------------------------------- + +By default, a model formset uses all fields in the model that are not marked +with ``editable=False``. However, this can be overridden at the formset level:: + + >>> AuthorFormSet = modelformset_factory(Author, fields=('name', 'title')) + +Using ``fields`` restricts the formset to use only the given fields. +Alternatively, you can take an "opt-out" approach, specifying which fields to +exclude:: + + >>> AuthorFormSet = modelformset_factory(Author, exclude=('birth_date',)) + +.. _saving-objects-in-the-formset: + +Saving objects in the formset +----------------------------- + +As with a ``ModelForm``, you can save the data as a model object. This is done +with the formset's ``save()`` method:: + + # Create a formset instance with POST data. + >>> formset = AuthorFormSet(request.POST) + + # Assuming all is valid, save the data. + >>> instances = formset.save() + +The ``save()`` method returns the instances that have been saved to the +database. If a given instance's data didn't change in the bound data, the +instance won't be saved to the database and won't be included in the return +value (``instances``, in the above example). + +Pass ``commit=False`` to return the unsaved model instances:: + + # don't save to the database + >>> instances = formset.save(commit=False) + >>> for instance in instances: + ... # do something with instance + ... instance.save() + +This gives you the ability to attach data to the instances before saving them +to the database. If your formset contains a ``ManyToManyField``, you'll also +need to call ``formset.save_m2m()`` to ensure the many-to-many relationships +are saved properly. + +.. _model-formsets-max-num: + +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. + +``max_num`` does not prevent existing objects from being displayed:: + + >>> Author.objects.order_by('name') + [<Author: Charles Baudelaire>, <Author: Paul Verlaine>, <Author: Walt Whitman>] + + >>> AuthorFormSet = modelformset_factory(Author, max_num=1) + >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name')) + >>> [x.name for x in formset.get_queryset()] + [u'Charles Baudelaire', u'Paul Verlaine', u'Walt Whitman'] + +If the value of ``max_num`` is greater than the number of existing related +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``:: + + >>> AuthorFormSet = modelformset_factory(Author, max_num=4, extra=2) + >>> formset = AuthorFormSet(queryset=Author.objects.order_by('name')) + >>> for form in formset.forms: + ... print form.as_table() + <tr><th><label for="id_form-0-name">Name:</label></th><td><input id="id_form-0-name" type="text" name="form-0-name" value="Charles Baudelaire" maxlength="100" /><input type="hidden" name="form-0-id" value="1" id="id_form-0-id" /></td></tr> + <tr><th><label for="id_form-1-name">Name:</label></th><td><input id="id_form-1-name" type="text" name="form-1-name" value="Paul Verlaine" maxlength="100" /><input type="hidden" name="form-1-id" value="3" id="id_form-1-id" /></td></tr> + <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. + +Using a model formset in a view +------------------------------- + +Model formsets are very similar to formsets. Let's say we want to present a +formset to edit ``Author`` model instances:: + + def manage_authors(request): + AuthorFormSet = modelformset_factory(Author) + if request.method == 'POST': + formset = AuthorFormSet(request.POST, request.FILES) + if formset.is_valid(): + formset.save() + # do something. + else: + formset = AuthorFormSet() + return render_to_response("manage_authors.html", { + "formset": formset, + }) + +As you can see, the view logic of a model formset isn't drastically different +than that of a "normal" formset. The only difference is that we call +``formset.save()`` to save the data into the database. (This was described +above, in :ref:`saving-objects-in-the-formset`.) + +Overiding ``clean()`` on a ``model_formset`` +-------------------------------------------- + +Just like with ``ModelForms``, by default the ``clean()`` method of a +``model_formset`` will validate that none of the items in the formset violate +the unique constraints on your model (either ``unique``, ``unique_together`` or +``unique_for_date|month|year``). If you want to overide the ``clean()`` method +on a ``model_formset`` and maintain this validation, you must call the parent +class's ``clean`` method:: + + class MyModelFormSet(BaseModelFormSet): + def clean(self): + super(MyModelFormSet, self).clean() + # example custom validation across forms in the formset: + for form in self.forms: + # your custom formset validation + +Using a custom queryset +----------------------- + +As stated earlier, you can override the default queryset used by the model +formset:: + + def manage_authors(request): + AuthorFormSet = modelformset_factory(Author) + if request.method == "POST": + formset = AuthorFormSet(request.POST, request.FILES, + queryset=Author.objects.filter(name__startswith='O')) + if formset.is_valid(): + formset.save() + # Do something. + else: + formset = AuthorFormSet(queryset=Author.objects.filter(name__startswith='O')) + return render_to_response("manage_authors.html", { + "formset": formset, + }) + +Note that we pass the ``queryset`` argument in both the ``POST`` and ``GET`` +cases in this example. + +Using the formset in the template +--------------------------------- + +.. highlight:: html+django + +There are three ways to render a formset in a Django template. + +First, you can let the formset do most of the work:: + + <form method="post" action=""> + {{ formset }} + </form> + +Second, you can manually render the formset, but let the form deal with +itself:: + + <form method="post" action=""> + {{ formset.management_form }} + {% for form in formset.forms %} + {{ form }} + {% endfor %} + </form> + +When you manually render the forms yourself, be sure to render the management +form as shown above. See the :ref:`management form documentation +<understanding-the-managementform>`. + +Third, you can manually render each field:: + + <form method="post" action=""> + {{ formset.management_form }} + {% for form in formset.forms %} + {% for field in form %} + {{ field.label_tag }}: {{ field }} + {% endfor %} + {% endfor %} + </form> + +If you opt to use this third method and you don't iterate over the fields with +a ``{% for %}`` loop, you'll need to render the primary key field. For example, +if you were rendering the ``name`` and ``age`` fields of a model:: + + <form method="post" action=""> + {{ formset.management_form }} + {% for form in formset.forms %} + {{ form.id }} + <ul> + <li>{{ form.name }}</li> + <li>{{ form.age }}</li> + </ul> + {% endfor %} + </form> + +Notice how we need to explicitly render ``{{ form.id }}``. This ensures that +the model formset, in the ``POST`` case, will work correctly. (This example +assumes a primary key named ``id``. If you've explicitly defined your own +primary key that isn't called ``id``, make sure it gets rendered.) + +.. highlight:: python + +Inline formsets +=============== + +Inline formsets is a small abstraction layer on top of model formsets. These +simplify the case of working with related objects via a foreign key. Suppose +you have these two models:: + + class Author(models.Model): + name = models.CharField(max_length=100) + + class Book(models.Model): + author = models.ForeignKey(Author) + title = models.CharField(max_length=100) + +If you want to create a formset that allows you to edit books belonging to +a particular author, you could do this:: + + >>> from django.forms.models import inlineformset_factory + >>> BookFormSet = inlineformset_factory(Author, Book) + >>> author = Author.objects.get(name=u'Mike Royko') + >>> formset = BookFormSet(instance=author) + +.. note:: + ``inlineformset_factory`` uses ``modelformset_factory`` and marks + ``can_delete=True``. + +More than one foreign key to the same model +------------------------------------------- + +If your model contains more than one foreign key to the same model, you'll +need to resolve the ambiguity manually using ``fk_name``. For example, consider +the following model:: + + class Friendship(models.Model): + from_friend = models.ForeignKey(Friend) + to_friend = models.ForeignKey(Friend) + length_in_months = models.IntegerField() + +To resolve this, you can use ``fk_name`` to ``inlineformset_factory``:: + + >>> FriendshipFormSet = inlineformset_factory(Friend, Friendship, fk_name="from_friend") + +Using an inline formset in a view +--------------------------------- + +You may want to provide a view that allows a user to edit the related objects +of a model. Here's how you can do that:: + + def manage_books(request, author_id): + author = Author.objects.get(pk=author_id) + BookInlineFormSet = inlineformset_factory(Author, Book) + if request.method == "POST": + formset = BookInlineFormSet(request.POST, request.FILES, instance=author) + if formset.is_valid(): + formset.save() + # Do something. + else: + formset = BookInlineFormSet(instance=author) + return render_to_response("manage_books.html", { + "formset": formset, + }) + +Notice how we pass ``instance`` in both the ``POST`` and ``GET`` cases. diff --git a/parts/django/docs/topics/generic-views.txt b/parts/django/docs/topics/generic-views.txt new file mode 100644 index 0000000..41e32c8 --- /dev/null +++ b/parts/django/docs/topics/generic-views.txt @@ -0,0 +1,501 @@ +============= +Generic views +============= + +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 ``talk_list`` view and a + ``registered_user_list`` view 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. The Django Weblog's + (http://www.djangoproject.com/weblog/) year, month, and + day archives are built with these, as would be a typical + newspaper's archives. + + * 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. + +Using generic views +=================== + +All of these views are used by creating configuration dictionaries in +your URLconf files and passing those dictionaries as the third member of the +URLconf tuple for a given pattern. + +For example, here's a simple URLconf you could use to present a static "about" +page:: + + from django.conf.urls.defaults import * + from django.views.generic.simple import direct_to_template + + urlpatterns = patterns('', + ('^about/$', direct_to_template, { + 'template': 'about.html' + }) + ) + +Though this might seem a bit "magical" at first glance -- look, a view with no +code! --, actually the ``direct_to_template`` view simply grabs information from +the extra-parameters dictionary and uses that information when rendering the +view. + +Because this generic view -- and all the others -- is a regular view function +like any other, we can reuse it inside our own views. As an example, let's +extend our "about" example to map URLs of the form ``/about/<whatever>/`` to +statically rendered ``about/<whatever>.html``. We'll do this by first modifying +the URLconf to point to a view function: + +.. parsed-literal:: + + from django.conf.urls.defaults import * + from django.views.generic.simple import direct_to_template + **from books.views import about_pages** + + urlpatterns = patterns('', + ('^about/$', direct_to_template, { + 'template': 'about.html' + }), + **('^about/(\\w+)/$', about_pages),** + ) + +Next, we'll write the ``about_pages`` view:: + + from django.http import Http404 + from django.template import TemplateDoesNotExist + from django.views.generic.simple import direct_to_template + + def about_pages(request, page): + try: + return direct_to_template(request, template="about/%s.html" % page) + except TemplateDoesNotExist: + raise Http404() + +Here we're treating ``direct_to_template`` like any other function. Since it +returns an ``HttpResponse``, we can simply return it as-is. The only slightly +tricky business here is dealing with missing templates. We don't want a +nonexistent template to cause a server error, so we catch +``TemplateDoesNotExist`` exceptions and return 404 errors instead. + +.. admonition:: Is there a security vulnerability here? + + Sharp-eyed readers may have noticed a possible security hole: we're + constructing the template name using interpolated content from the browser + (``template="about/%s.html" % page``). At first glance, this looks like a + classic *directory traversal* vulnerability. But is it really? + + Not exactly. Yes, a maliciously crafted value of ``page`` could cause + directory traversal, but although ``page`` *is* taken from the request URL, + not every value will be accepted. The key is in the URLconf: we're using + the regular expression ``\w+`` to match the ``page`` part of the URL, and + ``\w`` only accepts letters and numbers. Thus, any malicious characters + (dots and slashes, here) will be rejected by the URL resolver before they + reach the view itself. + +Generic views of objects +======================== + +The ``direct_to_template`` certainly is useful, but Django's generic views +really shine when it comes to presenting views on 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() + + def __unicode__(self): + return self.name + + class Meta: + ordering = ["-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.defaults import * + from django.views.generic import list_detail + from books.models import Publisher + + publisher_info = { + "queryset" : Publisher.objects.all(), + } + + urlpatterns = patterns('', + (r'^publishers/$', list_detail.object_list, publisher_info) + ) + +That's all the Python code we need to write. We still need to write a template, +however. We could explicitly tell the ``object_list`` view which template to use +by including a ``template_name`` key in the extra arguments dictionary, 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. + +.. 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/generic-views>` documents all the generic +views and all 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. + +Luckily, in nearly every one of these cases, there are ways to simply extend +generic views to handle a larger array of use cases. These situations usually +fall into a handful of patterns dealt with in the sections that follow. + +Making "friendly" template contexts +----------------------------------- + +You might have noticed that our sample publisher list template stores all the +books 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. A better name for that variable would be +``publisher_list``; that variable's content is pretty obvious. + +We can change the name of that variable easily with the ``template_object_name`` +argument: + +.. parsed-literal:: + + publisher_info = { + "queryset" : Publisher.objects.all(), + **"template_object_name" : "publisher",** + } + + urlpatterns = patterns('', + (r'^publishers/$', list_detail.object_list, publisher_info) + ) + +Providing a useful ``template_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 ``object_detail`` generic view provides the +publisher to the context, but it seems there's no way to get additional +information in that template. + +But there is: all generic views take an extra optional parameter, +``extra_context``. This is a dictionary of extra objects that will be added to +the template's context. So, to provide the list of all books on the detail +detail view, we'd use an info dict like this: + +.. parsed-literal:: + + from books.models import Publisher, **Book** + + publisher_info = { + "queryset" : Publisher.objects.all(), + "template_object_name" : "publisher", + **"extra_context" : {"book_list" : Book.objects.all()}** + } + +This would populate a ``{{ book_list }}`` variable in the template context. +This pattern can be used to pass any information down into the template for the +generic view. It's very handy. + +However, there's actually a subtle bug here -- can you spot it? + +The problem has to do with when the queries in ``extra_context`` are evaluated. +Because this example puts ``Book.objects.all()`` in the URLconf, it will +be evaluated only once (when the URLconf is first loaded). Once you add or +remove books, you'll notice that the generic view doesn't reflect those +changes until you reload the Web server (see :ref:`caching-and-querysets` +for more information about when QuerySets are cached and evaluated). + +.. note:: + + This problem doesn't apply to the ``queryset`` generic view argument. Since + Django knows that particular QuerySet should *never* be cached, the generic + view takes care of clearing the cache when each view is rendered. + +The solution is to use a callback in ``extra_context`` instead of a value. Any +callable (i.e., a function) that's passed to ``extra_context`` will be evaluated +when the view is rendered (instead of only once). You could do this with an +explicitly defined function: + +.. parsed-literal:: + + def get_books(): + return Book.objects.all() + + publisher_info = { + "queryset" : Publisher.objects.all(), + "template_object_name" : "publisher", + "extra_context" : **{"book_list" : get_books}** + } + +or you could use a less obvious but shorter version that relies on the fact that +``Book.objects.all`` is itself a callable: + +.. parsed-literal:: + + publisher_info = { + "queryset" : Publisher.objects.all(), + "template_object_name" : "publisher", + "extra_context" : **{"book_list" : Book.objects.all}** + } + +Notice the lack of parentheses after ``Book.objects.all``; this references +the function without actually calling it (which the generic view will do later). + +Viewing subsets of objects +-------------------------- + +Now let's take a closer look at this ``queryset`` key we've been using all +along. Most generic views take one of these ``queryset`` arguments -- it's how +the view knows which set of objects to display (see :doc:`/topics/db/queries` for +more information about ``QuerySet`` objects, and see the +:doc:`generic views reference</ref/generic-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: + +.. parsed-literal:: + + book_info = { + "queryset" : Book.objects.all().order_by("-publication_date"), + } + + urlpatterns = patterns('', + (r'^publishers/$', list_detail.object_list, publisher_info), + **(r'^books/$', list_detail.object_list, book_info),** + ) + + +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: + +.. parsed-literal:: + + **acme_books = {** + **"queryset": Book.objects.filter(publisher__name="Acme Publishing"),** + **"template_name" : "books/acme_list.html"** + **}** + + urlpatterns = patterns('', + (r'^publishers/$', list_detail.object_list, publisher_info), + **(r'^books/acme/$', list_detail.object_list, acme_books),** + ) + +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:`generic views reference</ref/generic-views>` for more details. + +Complex filtering with wrapper functions +---------------------------------------- + +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? We can "wrap" the ``object_list`` generic view to avoid writing a lot +of code by hand. As usual, we'll start by writing a URLconf: + +.. parsed-literal:: + + from books.views import books_by_publisher + + urlpatterns = patterns('', + (r'^publishers/$', list_detail.object_list, publisher_info), + **(r'^books/(\\w+)/$', books_by_publisher),** + ) + +Next, we'll write the ``books_by_publisher`` view itself:: + + from django.http import Http404 + from django.views.generic import list_detail + from books.models import Book, Publisher + + def books_by_publisher(request, name): + + # Look up the publisher (and raise a 404 if it can't be found). + try: + publisher = Publisher.objects.get(name__iexact=name) + except Publisher.DoesNotExist: + raise Http404 + + # Use the object_list view for the heavy lifting. + return list_detail.object_list( + request, + queryset = Book.objects.filter(publisher=publisher), + template_name = "books/books_by_publisher.html", + template_object_name = "books", + extra_context = {"publisher" : publisher} + ) + +This works because there's really nothing special about generic views -- they're +just Python functions. Like any view function, generic views expect a certain +set of arguments and return ``HttpResponse`` objects. Thus, it's incredibly easy +to wrap a small function around a generic view that does additional work before +(or after; see the next section) handing things off to the generic view. + +.. note:: + + Notice that in the preceding example we passed the current publisher being + displayed in the ``extra_context``. This is usually a good idea in wrappers + of this nature; it lets the template know which "parent" object is currently + being browsed. + +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 ``object_detail`` view, 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 author_detail + + urlpatterns = patterns('', + #... + **(r'^authors/(?P<author_id>\\d+)/$', author_detail),** + ) + +Then we'd write our wrapper function:: + + import datetime + from books.models import Author + from django.views.generic import list_detail + from django.shortcuts import get_object_or_404 + + def author_detail(request, author_id): + # Look up the Author (and raise a 404 if she's not found) + author = get_object_or_404(Author, pk=author_id) + + # Record the last accessed date + author.last_accessed = datetime.datetime.now() + author.save() + + # Show the detail page + return list_detail.object_detail( + request, + queryset = Author.objects.all(), + object_id = author_id, + ) + +.. note:: + + This code won't actually work unless you create a + ``books/author_detail.html`` template. + +We can use a similar idiom to alter the response returned by the generic view. +If we wanted to provide a downloadable plain-text version of the list of +authors, we could use a view like this:: + + def author_list_plaintext(request): + response = list_detail.object_list( + request, + queryset = Author.objects.all(), + mimetype = "text/plain", + template_name = "books/author_list.txt" + ) + response["Content-Disposition"] = "attachment; filename=authors.txt" + return response + +This works because the generic views return simple ``HttpResponse`` objects +that can be treated like dictionaries to set HTTP headers. This +``Content-Disposition`` business, by the way, instructs the browser to +download and save the page instead of displaying it in the browser. diff --git a/parts/django/docs/topics/http/_images/middleware.png b/parts/django/docs/topics/http/_images/middleware.png Binary files differnew file mode 100644 index 0000000..505c70a --- /dev/null +++ b/parts/django/docs/topics/http/_images/middleware.png diff --git a/parts/django/docs/topics/http/file-uploads.txt b/parts/django/docs/topics/http/file-uploads.txt new file mode 100644 index 0000000..a06a1ca --- /dev/null +++ b/parts/django/docs/topics/http/file-uploads.txt @@ -0,0 +1,394 @@ +============ +File Uploads +============ + +.. currentmodule:: django.core.files + +.. versionadded:: 1.0 + +When Django handles a file upload, the file data ends up placed in +:attr:`request.FILES <django.http.HttpRequest.FILES>` (for more on the +``request`` object see the documentation for :doc:`request and response objects +</ref/request-response>`). This document explains how files are stored on disk +and in memory, and how to customize the default behavior. + +Basic file uploads +================== + +Consider a simple form containing a :class:`~django.forms.FileField`:: + + from django import forms + + class UploadFileForm(forms.Form): + title = forms.CharField(max_length=50) + file = forms.FileField() + +A view handling this form will receive the file data in +:attr:`request.FILES <django.http.HttpRequest.FILES>`, which is a dictionary +containing a key for each :class:`~django.forms.FileField` (or +:class:`~django.forms.ImageField`, or other :class:`~django.forms.FileField` +subclass) in the form. So the data from the above form would +be accessible as ``request.FILES['file']``. + +Note that :attr:`request.FILES <django.http.HttpRequest.FILES>` will only +contain data if the request method was ``POST`` and the ``<form>`` that posted +the request has the attribute ``enctype="multipart/form-data"``. Otherwise, +``request.FILES`` will be empty. + +Most of the time, you'll simply pass the file data from ``request`` into the +form as described in :ref:`binding-uploaded-files`. This would look +something like:: + + from django.http import HttpResponseRedirect + from django.shortcuts import render_to_response + + # Imaginary function to handle an uploaded file. + from somewhere import handle_uploaded_file + + def upload_file(request): + if request.method == 'POST': + form = UploadFileForm(request.POST, request.FILES) + if form.is_valid(): + handle_uploaded_file(request.FILES['file']) + return HttpResponseRedirect('/success/url/') + else: + form = UploadFileForm() + return render_to_response('upload.html', {'form': form}) + +Notice that we have to pass :attr:`request.FILES <django.http.HttpRequest.FILES>` +into the form's constructor; this is how file data gets bound into a form. + +Handling uploaded files +----------------------- + +The final piece of the puzzle is handling the actual file data from +:attr:`request.FILES <django.http.HttpRequest.FILES>`. Each entry in this +dictionary is an ``UploadedFile`` object -- a simple wrapper around an uploaded +file. You'll usually use one of these methods to access the uploaded content: + + ``UploadedFile.read()`` + Read the entire uploaded data from the file. Be careful with this + method: if the uploaded file is huge it can overwhelm your system if you + try to read it into memory. You'll probably want to use ``chunks()`` + instead; see below. + + ``UploadedFile.multiple_chunks()`` + Returns ``True`` if the uploaded file is big enough to require + reading in multiple chunks. By default this will be any file + larger than 2.5 megabytes, but that's configurable; see below. + + ``UploadedFile.chunks()`` + A generator returning chunks of the file. If ``multiple_chunks()`` is + ``True``, you should use this method in a loop instead of ``read()``. + + In practice, it's often easiest simply to use ``chunks()`` all the time; + see the example below. + + ``UploadedFile.name`` + The name of the uploaded file (e.g. ``my_file.txt``). + + ``UploadedFile.size`` + The size, in bytes, of the uploaded file. + +There are a few other methods and attributes available on ``UploadedFile`` +objects; see `UploadedFile objects`_ for a complete reference. + +Putting it all together, here's a common way you might handle an uploaded file:: + + def handle_uploaded_file(f): + destination = open('some/file/name.txt', 'wb+') + for chunk in f.chunks(): + destination.write(chunk) + destination.close() + +Looping over ``UploadedFile.chunks()`` instead of using ``read()`` ensures that +large files don't overwhelm your system's memory. + +Where uploaded data is stored +----------------------------- + +Before you save uploaded files, the data needs to be stored somewhere. + +By default, if an uploaded file is smaller than 2.5 megabytes, Django will hold +the entire contents of the upload in memory. This means that saving the file +involves only a read from memory and a write to disk and thus is very fast. + +However, if an uploaded file is too large, Django will write the uploaded file +to a temporary file stored in your system's temporary directory. On a Unix-like +platform this means you can expect Django to generate a file called something +like ``/tmp/tmpzfp6I6.upload``. If an upload is large enough, you can watch this +file grow in size as Django streams the data onto disk. + +These specifics -- 2.5 megabytes; ``/tmp``; etc. -- are simply "reasonable +defaults". Read on for details on how you can customize or completely replace +upload behavior. + +Changing upload handler behavior +-------------------------------- + +Three settings control Django's file upload behavior: + + :setting:`FILE_UPLOAD_MAX_MEMORY_SIZE` + The maximum size, in bytes, for files that will be uploaded into memory. + Files larger than :setting:`FILE_UPLOAD_MAX_MEMORY_SIZE` will be + streamed to disk. + + Defaults to 2.5 megabytes. + + :setting:`FILE_UPLOAD_TEMP_DIR` + The directory where uploaded files larger than + :setting:`FILE_UPLOAD_MAX_MEMORY_SIZE` will be stored. + + Defaults to your system's standard temporary directory (i.e. ``/tmp`` on + most Unix-like systems). + + :setting:`FILE_UPLOAD_PERMISSIONS` + The numeric mode (i.e. ``0644``) to set newly uploaded files to. For + more information about what these modes mean, see the `documentation for + os.chmod`_ + + If this isn't given or is ``None``, you'll get operating-system + dependent behavior. On most platforms, temporary files will have a mode + of ``0600``, and files saved from memory will be saved using the + system's standard umask. + + .. warning:: + + If you're not familiar with file modes, please note that the leading + ``0`` is very important: it indicates an octal number, which is the + way that modes must be specified. If you try to use ``644``, you'll + get totally incorrect behavior. + + **Always prefix the mode with a 0.** + + :setting:`FILE_UPLOAD_HANDLERS` + The actual handlers for uploaded files. Changing this setting allows + complete customization -- even replacement -- of Django's upload + process. See `upload handlers`_, below, for details. + + Defaults to:: + + ("django.core.files.uploadhandler.MemoryFileUploadHandler", + "django.core.files.uploadhandler.TemporaryFileUploadHandler",) + + Which means "try to upload to memory first, then fall back to temporary + files." + +.. _documentation for os.chmod: http://docs.python.org/library/os.html#os.chmod + +``UploadedFile`` objects +======================== + +.. class:: UploadedFile + +In addition to those inherited from :class:`File`, all ``UploadedFile`` objects +define the following methods/attributes: + + ``UploadedFile.content_type`` + The content-type header uploaded with the file (e.g. ``text/plain`` or + ``application/pdf``). Like any data supplied by the user, you shouldn't + trust that the uploaded file is actually this type. You'll still need to + validate that the file contains the content that the content-type header + claims -- "trust but verify." + + ``UploadedFile.charset`` + For ``text/*`` content-types, the character set (i.e. ``utf8``) supplied + by the browser. Again, "trust but verify" is the best policy here. + + ``UploadedFile.temporary_file_path()`` + Only files uploaded onto disk will have this method; it returns the full + path to the temporary uploaded file. + +.. note:: + + Like regular Python files, you can read the file line-by-line simply by + iterating over the uploaded file: + + .. code-block:: python + + for line in uploadedfile: + do_something_with(line) + + However, *unlike* standard Python files, :class:`UploadedFile` only + understands ``\n`` (also known as "Unix-style") line endings. If you know + that you need to handle uploaded files with different line endings, you'll + need to do so in your view. + +Upload Handlers +=============== + +When a user uploads a file, Django passes off the file data to an *upload +handler* -- a small class that handles file data as it gets uploaded. Upload +handlers are initially defined in the ``FILE_UPLOAD_HANDLERS`` setting, which +defaults to:: + + ("django.core.files.uploadhandler.MemoryFileUploadHandler", + "django.core.files.uploadhandler.TemporaryFileUploadHandler",) + +Together the ``MemoryFileUploadHandler`` and ``TemporaryFileUploadHandler`` +provide Django's default file upload behavior of reading small files into memory +and large ones onto disk. + +You can write custom handlers that customize how Django handles files. You +could, for example, use custom handlers to enforce user-level quotas, compress +data on the fly, render progress bars, and even send data to another storage +location directly without storing it locally. + +Modifying upload handlers on the fly +------------------------------------ + +Sometimes particular views require different upload behavior. In these cases, +you can override upload handlers on a per-request basis by modifying +``request.upload_handlers``. By default, this list will contain the upload +handlers given by ``FILE_UPLOAD_HANDLERS``, but you can modify the list as you +would any other list. + +For instance, suppose you've written a ``ProgressBarUploadHandler`` that +provides feedback on upload progress to some sort of AJAX widget. You'd add this +handler to your upload handlers like this:: + + request.upload_handlers.insert(0, ProgressBarUploadHandler()) + +You'd probably want to use ``list.insert()`` in this case (instead of +``append()``) because a progress bar handler would need to run *before* any +other handlers. Remember, the upload handlers are processed in order. + +If you want to replace the upload handlers completely, you can just assign a new +list:: + + request.upload_handlers = [ProgressBarUploadHandler()] + +.. note:: + + You can only modify upload handlers *before* accessing + ``request.POST`` or ``request.FILES`` -- it doesn't make sense to + change upload handlers after upload handling has already + started. If you try to modify ``request.upload_handlers`` after + reading from ``request.POST`` or ``request.FILES`` Django will + throw an error. + + Thus, you should always modify uploading handlers as early in your view as + possible. + + Also, ``request.POST`` is accessed by + :class:`~django.middleware.csrf.CsrfViewMiddleware` which is enabled by + default. This means you will probably need to use + :func:`~django.views.decorators.csrf.csrf_exempt` on your view to allow you + to change the upload handlers. Assuming you do need CSRF protection, you + will then need to use :func:`~django.views.decorators.csrf.csrf_protect` on + the function that actually processes the request. Note that this means that + the handlers may start receiving the file upload before the CSRF checks have + been done. Example code: + + .. code-block:: python + + from django.views.decorators.csrf import csrf_exempt, csrf_protect + + @csrf_exempt + def upload_file_view(request): + request.upload_handlers.insert(0, ProgressBarUploadHandler()) + return _upload_file_view(request) + + @csrf_protect + def _upload_file_view(request): + ... # Process request + + +Writing custom upload handlers +------------------------------ + +All file upload handlers should be subclasses of +``django.core.files.uploadhandler.FileUploadHandler``. You can define upload +handlers wherever you wish. + +Required methods +~~~~~~~~~~~~~~~~ + +Custom file upload handlers **must** define the following methods: + + ``FileUploadHandler.receive_data_chunk(self, raw_data, start)`` + Receives a "chunk" of data from the file upload. + + ``raw_data`` is a byte string containing the uploaded data. + + ``start`` is the position in the file where this ``raw_data`` chunk + begins. + + The data you return will get fed into the subsequent upload handlers' + ``receive_data_chunk`` methods. In this way, one handler can be a + "filter" for other handlers. + + Return ``None`` from ``receive_data_chunk`` to sort-circuit remaining + upload handlers from getting this chunk.. This is useful if you're + storing the uploaded data yourself and don't want future handlers to + store a copy of the data. + + If you raise a ``StopUpload`` or a ``SkipFile`` exception, the upload + will abort or the file will be completely skipped. + + ``FileUploadHandler.file_complete(self, file_size)`` + Called when a file has finished uploading. + + The handler should return an ``UploadedFile`` object that will be stored + in ``request.FILES``. Handlers may also return ``None`` to indicate that + the ``UploadedFile`` object should come from subsequent upload handlers. + +Optional methods +~~~~~~~~~~~~~~~~ + +Custom upload handlers may also define any of the following optional methods or +attributes: + + ``FileUploadHandler.chunk_size`` + Size, in bytes, of the "chunks" Django should store into memory and feed + into the handler. That is, this attribute controls the size of chunks + fed into ``FileUploadHandler.receive_data_chunk``. + + For maximum performance the chunk sizes should be divisible by ``4`` and + should not exceed 2 GB (2\ :sup:`31` bytes) in size. When there are + multiple chunk sizes provided by multiple handlers, Django will use the + smallest chunk size defined by any handler. + + The default is 64*2\ :sup:`10` bytes, or 64 KB. + + ``FileUploadHandler.new_file(self, field_name, file_name, content_type, content_length, charset)`` + Callback signaling that a new file upload is starting. This is called + before any data has been fed to any upload handlers. + + ``field_name`` is a string name of the file ``<input>`` field. + + ``file_name`` is the unicode filename that was provided by the browser. + + ``content_type`` is the MIME type provided by the browser -- E.g. + ``'image/jpeg'``. + + ``content_length`` is the length of the image given by the browser. + Sometimes this won't be provided and will be ``None``. + + ``charset`` is the character set (i.e. ``utf8``) given by the browser. + Like ``content_length``, this sometimes won't be provided. + + This method may raise a ``StopFutureHandlers`` exception to prevent + future handlers from handling this file. + + ``FileUploadHandler.upload_complete(self)`` + Callback signaling that the entire upload (all files) has completed. + + ``FileUploadHandler.handle_raw_input(self, input_data, META, content_length, boundary, encoding)`` + Allows the handler to completely override the parsing of the raw + HTTP input. + + ``input_data`` is a file-like object that supports ``read()``-ing. + + ``META`` is the same object as ``request.META``. + + ``content_length`` is the length of the data in ``input_data``. Don't + read more than ``content_length`` bytes from ``input_data``. + + ``boundary`` is the MIME boundary for this request. + + ``encoding`` is the encoding of the request. + + Return ``None`` if you want upload handling to continue, or a tuple of + ``(POST, FILES)`` if you want to return the new data structures suitable + for the request directly. diff --git a/parts/django/docs/topics/http/generic-views.txt b/parts/django/docs/topics/http/generic-views.txt new file mode 100644 index 0000000..15f895e --- /dev/null +++ b/parts/django/docs/topics/http/generic-views.txt @@ -0,0 +1,5 @@ +============= +Generic views +============= + +See :doc:`/ref/generic-views`. diff --git a/parts/django/docs/topics/http/index.txt b/parts/django/docs/topics/http/index.txt new file mode 100644 index 0000000..5ef776d --- /dev/null +++ b/parts/django/docs/topics/http/index.txt @@ -0,0 +1,15 @@ +Handling HTTP requests +====================== + +Information on handling HTTP requests in Django: + +.. toctree:: + :maxdepth: 1 + + urls + views + file-uploads + shortcuts + generic-views + middleware + sessions diff --git a/parts/django/docs/topics/http/middleware.txt b/parts/django/docs/topics/http/middleware.txt new file mode 100644 index 0000000..d376c6b --- /dev/null +++ b/parts/django/docs/topics/http/middleware.txt @@ -0,0 +1,179 @@ +========== +Middleware +========== + +Middleware is a framework of hooks into Django's request/response processing. +It's a light, low-level "plugin" system for globally altering Django's input +and/or output. + +Each middleware component is responsible for doing some specific function. For +example, Django includes a middleware component, ``XViewMiddleware``, that adds +an ``"X-View"`` HTTP header to every response to a ``HEAD`` request. + +This document explains how middleware works, how you activate middleware, and +how to write your own middleware. Django ships with some built-in middleware +you can use right out of the box; they're documented in the :doc:`built-in +middleware reference </ref/middleware>`. + +Activating middleware +===================== + +To activate a middleware component, add it to the :setting:`MIDDLEWARE_CLASSES` +list in your Django settings. In :setting:`MIDDLEWARE_CLASSES`, each middleware +component is represented by a string: the full Python path to the middleware's +class name. For example, here's the default :setting:`MIDDLEWARE_CLASSES` +created by :djadmin:`django-admin.py startproject <startproject>`:: + + MIDDLEWARE_CLASSES = ( + 'django.middleware.common.CommonMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + ) + +During the request phases (:meth:`process_request` and :meth:`process_view` +middleware), Django applies middleware in the order it's defined in +:setting:`MIDDLEWARE_CLASSES`, top-down. During the response phases +(:meth:`process_response` and :meth:`process_exception` middleware), the +classes are applied in reverse order, from the bottom up. You can think of it +like an onion: each middleware class is a "layer" that wraps the view: + +.. image:: _images/middleware.png + :width: 502 + :height: 417 + :alt: Middleware application order. + +A Django installation doesn't require any middleware -- e.g., +:setting:`MIDDLEWARE_CLASSES` can be empty, if you'd like -- but it's strongly +suggested that you at least use +:class:`~django.middleware.common.CommonMiddleware`. + +Writing your own middleware +=========================== + +Writing your own middleware is easy. Each middleware component is a single +Python class that defines one or more of the following methods: + +.. _request-middleware: + +``process_request`` +------------------- + +.. method:: process_request(self, request) + +``request`` is an :class:`~django.http.HttpRequest` object. This method is +called on each request, before Django decides which view to execute. + +``process_request()`` should return either ``None`` or an +:class:`~django.http.HttpResponse` object. If it returns ``None``, Django will +continue processing this request, executing any other middleware and, then, the +appropriate view. If it returns an :class:`~django.http.HttpResponse` object, +Django won't bother calling ANY other request, view or exception middleware, or +the appropriate view; it'll return that :class:`~django.http.HttpResponse`. +Response middleware is always called on every response. + +.. _view-middleware: + +``process_view`` +---------------- + +.. method:: process_view(self, request, view_func, view_args, view_kwargs) + +``request`` is an :class:`~django.http.HttpRequest` object. ``view_func`` is +the Python function that Django is about to use. (It's the actual function +object, not the name of the function as a string.) ``view_args`` is a list of +positional arguments that will be passed to the view, and ``view_kwargs`` is a +dictionary of keyword arguments that will be passed to the view. Neither +``view_args`` nor ``view_kwargs`` include the first view argument +(``request``). + +``process_view()`` is called just before Django calls the view. It should +return either ``None`` or an :class:`~django.http.HttpResponse` object. If it +returns ``None``, Django will continue processing this request, executing any +other ``process_view()`` middleware and, then, the appropriate view. If it +returns an :class:`~django.http.HttpResponse` object, Django won't bother +calling ANY other request, view or exception middleware, or the appropriate +view; it'll return that :class:`~django.http.HttpResponse`. Response +middleware is always called on every response. + +.. _response-middleware: + +``process_response`` +-------------------- + +.. method:: process_response(self, request, response) + +``request`` is an :class:`~django.http.HttpRequest` object. ``response`` is the +:class:`~django.http.HttpResponse` object returned by a Django view. + +``process_response()`` must return an :class:`~django.http.HttpResponse` +object. It could alter the given ``response``, or it could create and return a +brand-new :class:`~django.http.HttpResponse`. + +Unlike the ``process_request()`` and ``process_view()`` methods, the +``process_response()`` method is always called, even if the ``process_request()`` +and ``process_view()`` methods of the same middleware class were skipped because +an earlier middleware method returned an :class:`~django.http.HttpResponse` +(this means that your ``process_response()`` method cannot rely on setup done in +``process_request()``, for example). In addition, during the response phase the +classes are applied in reverse order, from the bottom up. This means classes +defined at the end of :setting:`MIDDLEWARE_CLASSES` will be run first. + +.. _exception-middleware: + +``process_exception`` +--------------------- + +.. method:: process_exception(self, request, exception) + +``request`` is an :class:`~django.http.HttpRequest` object. ``exception`` is an +``Exception`` object raised by the view function. + +Django calls ``process_exception()`` when a view raises an exception. +``process_exception()`` should return either ``None`` or an +:class:`~django.http.HttpResponse` object. If it returns an +:class:`~django.http.HttpResponse` object, the response will be returned to +the browser. Otherwise, default exception handling kicks in. + +Again, middleware are run in reverse order during the response phase, which +includes ``process_exception``. If an exception middleware return a response, +the middleware classes above that middleware will not be called at all. + +``__init__`` +------------ + +Most middleware classes won't need an initializer since middleware classes are +essentially placeholders for the ``process_*`` methods. If you do need some +global state you may use ``__init__`` to set up. However, keep in mind a couple +of caveats: + + * Django initializes your middleware without any arguments, so you can't + 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. + +Marking middleware as unused +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It's sometimes useful to determine at run-time whether a piece of middleware +should be used. In these cases, your middleware's ``__init__`` method may raise +``django.core.exceptions.MiddlewareNotUsed``. Django will then remove that +piece of middleware from the middleware process. + +Guidelines +---------- + + * Middleware classes don't have to subclass anything. + + * The middleware class can live anywhere on your Python path. All Django + cares about is that the :setting:`MIDDLEWARE_CLASSES` setting includes + the path to it. + + * Feel free to look at :doc:`Django's available middleware + </ref/middleware>` for examples. + + * If you write a middleware component that you think would be useful to + other people, contribute to the community! :doc:`Let us know + </internals/contributing>`, and we'll consider adding it to Django. diff --git a/parts/django/docs/topics/http/sessions.txt b/parts/django/docs/topics/http/sessions.txt new file mode 100644 index 0000000..8a0f0d4 --- /dev/null +++ b/parts/django/docs/topics/http/sessions.txt @@ -0,0 +1,529 @@ +=================== +How to use sessions +=================== + +.. module:: django.contrib.sessions + :synopsis: Provides session management for Django projects. + +Django provides full support for anonymous sessions. The session framework lets +you store and retrieve arbitrary data on a per-site-visitor basis. It stores +data on the server side and abstracts the sending and receiving of cookies. +Cookies contain a session ID -- not the data itself. + +Enabling sessions +================= + +Sessions are implemented via a piece of :doc:`middleware </ref/middleware>`. + +To enable session functionality, do the following: + + * Edit the ``MIDDLEWARE_CLASSES`` setting and make sure + ``MIDDLEWARE_CLASSES`` contains ``'django.contrib.sessions.middleware.SessionMiddleware'``. + The default ``settings.py`` created by ``django-admin.py startproject`` has + ``SessionMiddleware`` activated. + +If you don't want to use sessions, you might as well remove the +``SessionMiddleware`` line from ``MIDDLEWARE_CLASSES`` and ``'django.contrib.sessions'`` +from your ``INSTALLED_APPS``. It'll save you a small bit of overhead. + +Configuring the session engine +============================== + +.. versionadded:: 1.0 + +By default, Django stores sessions in your database (using the model +``django.contrib.sessions.models.Session``). Though this is convenient, in +some setups it's faster to store session data elsewhere, so Django can be +configured to store session data on your filesystem or in your cache. + +Using database-backed sessions +------------------------------ + +If you want to use a database-backed session, you need to add +``'django.contrib.sessions'`` to your ``INSTALLED_APPS`` setting. + +Once you have configured your installation, run ``manage.py syncdb`` +to install the single database table that stores session data. + +Using cached sessions +--------------------- + +For better performance, you may want to use a cache-based session backend. + +.. versionchanged:: 1.1 + Django 1.0 did not include the ``cached_db`` session backend. + +To store session data using Django's cache system, you'll first need to make +sure you've configured your cache; see the :doc:`cache documentation +</topics/cache>` for details. + +.. warning:: + + You should only use cache-based sessions if you're using the Memcached + cache backend. The local-memory cache backend doesn't retain data long + enough to be a good choice, and it'll be faster to use file or database + sessions directly instead of sending everything through the file or + database cache backends. + +Once your cache is configured, you've got two choices for how to store data in +the cache: + + * Set :setting:`SESSION_ENGINE` to + ``"django.contrib.sessions.backends.cache"`` for a simple caching session + store. Session data will be stored directly your cache. However, session + data may not be persistent: cached data can be evicted if the cache fills + up or if the cache server is restarted. + + * For persistent, cached data, set :setting:`SESSION_ENGINE` to + ``"django.contrib.sessions.backends.cached_db"``. This uses a + write-through cache -- every write to the cache will also be written to + the database. Session reads only use the database if the data is not + already in the cache. + +Both session stores are quite fast, but the simple cache is faster because it +disregards persistence. In most cases, the ``cached_db`` backend will be fast +enough, but if you need that last bit of performance, and are willing to let +session data be expunged from time to time, the ``cache`` backend is for you. + +If you use the ``cached_db`` session backend, you also need to follow the +configuration instructions for the `using database-backed sessions`_. + +Using file-based sessions +------------------------- + +To use file-based sessions, set the ``SESSION_ENGINE`` setting to +``"django.contrib.sessions.backends.file"``. + +You might also want to set the ``SESSION_FILE_PATH`` setting (which defaults +to output from ``tempfile.gettempdir()``, most likely ``/tmp``) to control +where Django stores session files. Be sure to check that your Web server has +permissions to read and write to this location. + + +Using sessions in views +======================= + +When ``SessionMiddleware`` is activated, each ``HttpRequest`` object -- the +first argument to any Django view function -- will have a ``session`` +attribute, which is a dictionary-like object. You can read it and write to it. + +A session object has the following standard dictionary methods: + + * ``__getitem__(key)`` + + Example: ``fav_color = request.session['fav_color']`` + + * ``__setitem__(key, value)`` + + Example: ``request.session['fav_color'] = 'blue'`` + + * ``__delitem__(key)`` + + Example: ``del request.session['fav_color']``. This raises ``KeyError`` + if the given ``key`` isn't already in the session. + + * ``__contains__(key)`` + + Example: ``'fav_color' in request.session`` + + * ``get(key, default=None)`` + + Example: ``fav_color = request.session.get('fav_color', 'red')`` + + * ``keys()`` + + * ``items()`` + + * ``setdefault()`` + + * ``clear()`` + +.. versionadded:: 1.0 + ``setdefault()`` and ``clear()`` are new in this version. + +It also has these methods: + + * ``flush()`` + + .. versionadded:: 1.0 + + Delete the current session data from the session and regenerate the + session key value that is sent back to the user in the cookie. This is + used if you want to ensure that the previous session data can't be + accessed again from the user's browser (for example, the + :func:`django.contrib.auth.logout()` function calls it). + + * ``set_test_cookie()`` + + Sets a test cookie to determine whether the user's browser supports + cookies. Due to the way cookies work, you won't be able to test this + until the user's next page request. See `Setting test cookies`_ below for + more information. + + * ``test_cookie_worked()`` + + Returns either ``True`` or ``False``, depending on whether the user's + browser accepted the test cookie. Due to the way cookies work, you'll + have to call ``set_test_cookie()`` on a previous, separate page request. + See `Setting test cookies`_ below for more information. + + * ``delete_test_cookie()`` + + Deletes the test cookie. Use this to clean up after yourself. + + * ``set_expiry(value)`` + + .. versionadded:: 1.0 + + Sets the expiration time for the session. You can pass a number of + different values: + + * If ``value`` is an integer, the session will expire after that + many seconds of inactivity. For example, calling + ``request.session.set_expiry(300)`` would make the session expire + in 5 minutes. + + * If ``value`` is a ``datetime`` or ``timedelta`` object, the + session will expire at that specific date/time. + + * If ``value`` is ``0``, the user's session cookie will expire + when the user's Web browser is closed. + + * If ``value`` is ``None``, the session reverts to using the global + session expiry policy. + + Reading a session is not considered activity for expiration + purposes. Session expiration is computed from the last time the + session was *modified*. + + * ``get_expiry_age()`` + + .. versionadded:: 1.0 + + Returns the number of seconds until this session expires. For sessions + with no custom expiration (or those set to expire at browser close), this + will equal ``settings.SESSION_COOKIE_AGE``. + + * ``get_expiry_date()`` + + .. versionadded:: 1.0 + + Returns the date this session will expire. For sessions with no custom + expiration (or those set to expire at browser close), this will equal the + date ``settings.SESSION_COOKIE_AGE`` seconds from now. + + * ``get_expire_at_browser_close()`` + + .. versionadded:: 1.0 + + Returns either ``True`` or ``False``, depending on whether the user's + session cookie will expire when the user's Web browser is closed. + +You can edit ``request.session`` at any point in your view. You can edit it +multiple times. + +Session object guidelines +------------------------- + + * Use normal Python strings as dictionary keys on ``request.session``. This + is more of a convention than a hard-and-fast rule. + + * Session dictionary keys that begin with an underscore are reserved for + internal use by Django. + + * Don't override ``request.session`` with a new object, and don't access or + set its attributes. Use it like a Python dictionary. + +Examples +-------- + +This simplistic view sets a ``has_commented`` variable to ``True`` after a user +posts a comment. It doesn't let a user post a comment more than once:: + + def post_comment(request, new_comment): + if request.session.get('has_commented', False): + return HttpResponse("You've already commented.") + c = comments.Comment(comment=new_comment) + c.save() + request.session['has_commented'] = True + return HttpResponse('Thanks for your comment!') + +This simplistic view logs in a "member" of the site:: + + def login(request): + m = Member.objects.get(username=request.POST['username']) + if m.password == request.POST['password']: + request.session['member_id'] = m.id + return HttpResponse("You're logged in.") + else: + return HttpResponse("Your username and password didn't match.") + +...And this one logs a member out, according to ``login()`` above:: + + def logout(request): + try: + del request.session['member_id'] + except KeyError: + pass + return HttpResponse("You're logged out.") + +The standard ``django.contrib.auth.logout()`` function actually does a bit +more than this to prevent inadvertent data leakage. It calls +``request.session.flush()``. We are using this example as a demonstration of +how to work with session objects, not as a full ``logout()`` implementation. + +Setting test cookies +==================== + +As a convenience, Django provides an easy way to test whether the user's +browser accepts cookies. Just call ``request.session.set_test_cookie()`` in a +view, and call ``request.session.test_cookie_worked()`` in a subsequent view -- +not in the same view call. + +This awkward split between ``set_test_cookie()`` and ``test_cookie_worked()`` +is necessary due to the way cookies work. When you set a cookie, you can't +actually tell whether a browser accepted it until the browser's next request. + +It's good practice to use ``delete_test_cookie()`` to clean up after yourself. +Do this after you've verified that the test cookie worked. + +Here's a typical usage example:: + + def login(request): + if request.method == 'POST': + if request.session.test_cookie_worked(): + request.session.delete_test_cookie() + return HttpResponse("You're logged in.") + else: + return HttpResponse("Please enable cookies and try again.") + request.session.set_test_cookie() + return render_to_response('foo/login_form.html') + +Using sessions out of views +=========================== + +.. versionadded:: 1.0 + +An API is available to manipulate session data outside of a view:: + + >>> from django.contrib.sessions.backends.db import SessionStore + >>> s = SessionStore(session_key='2b1189a188b44ad18c35e113ac6ceead') + >>> s['last_login'] = datetime.datetime(2005, 8, 20, 13, 35, 10) + >>> s['last_login'] + datetime.datetime(2005, 8, 20, 13, 35, 0) + >>> s.save() + +If you're using the ``django.contrib.sessions.backends.db`` backend, each +session is just a normal Django model. The ``Session`` model is defined in +``django/contrib/sessions/models.py``. Because it's a normal model, you can +access sessions using the normal Django database API:: + + >>> from django.contrib.sessions.models import Session + >>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead') + >>> s.expire_date + datetime.datetime(2005, 8, 20, 13, 35, 12) + +Note that you'll need to call ``get_decoded()`` to get the session dictionary. +This is necessary because the dictionary is stored in an encoded format:: + + >>> s.session_data + 'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...' + >>> s.get_decoded() + {'user_id': 42} + +When sessions are saved +======================= + +By default, Django only saves to the session database when the session has been +modified -- that is if any of its dictionary values have been assigned or +deleted:: + + # Session is modified. + request.session['foo'] = 'bar' + + # Session is modified. + del request.session['foo'] + + # Session is modified. + request.session['foo'] = {} + + # Gotcha: Session is NOT modified, because this alters + # request.session['foo'] instead of request.session. + request.session['foo']['bar'] = 'baz' + +In the last case of the above example, we can tell the session object +explicitly that it has been modified by setting the ``modified`` attribute on +the session object:: + + request.session.modified = True + +To change this default behavior, set the ``SESSION_SAVE_EVERY_REQUEST`` setting +to ``True``. If ``SESSION_SAVE_EVERY_REQUEST`` is ``True``, Django will save +the session to the database on every single request. + +Note that the session cookie is only sent when a session has been created or +modified. If ``SESSION_SAVE_EVERY_REQUEST`` is ``True``, the session cookie +will be sent on every request. + +Similarly, the ``expires`` part of a session cookie is updated each time the +session cookie is sent. + +Browser-length sessions vs. persistent sessions +=============================================== + +You can control whether the session framework uses browser-length sessions vs. +persistent sessions with the ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` setting. + +By default, ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` is set to ``False``, which +means session cookies will be stored in users' browsers for as long as +``SESSION_COOKIE_AGE``. Use this if you don't want people to have to log in +every time they open a browser. + +If ``SESSION_EXPIRE_AT_BROWSER_CLOSE`` is set to ``True``, Django will use +browser-length cookies -- cookies that expire as soon as the user closes his or +her browser. Use this if you want people to have to log in every time they open +a browser. + +.. versionadded:: 1.0 + +This setting is a global default and can be overwritten at a per-session level +by explicitly calling ``request.session.set_expiry()`` as described above in +`using sessions in views`_. + +Clearing the session table +========================== + +If you're using the database backend, note that session data can accumulate in +the ``django_session`` database table and Django does *not* provide automatic +purging. Therefore, it's your job to purge expired sessions on a regular basis. + +To understand this problem, consider what happens when a user uses a session. +When a user logs in, Django adds a row to the ``django_session`` database +table. Django updates this row each time the session data changes. If the user +logs out manually, Django deletes the row. But if the user does *not* log out, +the row never gets deleted. + +Django provides a sample clean-up script: ``django-admin.py cleanup``. +That script deletes any session in the session table whose ``expire_date`` is +in the past -- but your application may have different requirements. + +Settings +======== + +A few :doc:`Django settings </ref/settings>` give you control over session behavior: + +SESSION_ENGINE +-------------- + +.. versionadded:: 1.0 + +.. versionchanged:: 1.1 + The ``cached_db`` backend was added + +Default: ``django.contrib.sessions.backends.db`` + +Controls where Django stores session data. Valid values are: + + * ``'django.contrib.sessions.backends.db'`` + * ``'django.contrib.sessions.backends.file'`` + * ``'django.contrib.sessions.backends.cache'`` + * ``'django.contrib.sessions.backends.cached_db'`` + +See `configuring the session engine`_ for more details. + +SESSION_FILE_PATH +----------------- + +.. versionadded:: 1.0 + +Default: ``/tmp/`` + +If you're using file-based session storage, this sets the directory in +which Django will store session data. + +SESSION_COOKIE_AGE +------------------ + +Default: ``1209600`` (2 weeks, in seconds) + +The age of session cookies, in seconds. + +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 +``None`` for a standard domain cookie. + +SESSION_COOKIE_NAME +------------------- + +Default: ``'sessionid'`` + +The name of the cookie to use for sessions. This can be whatever you want. + +SESSION_COOKIE_PATH +------------------- + +.. versionadded:: 1.0 + +Default: ``'/'`` + +The path set on the session cookie. This should either match the URL path of +your Django installation or be parent of that path. + +This is useful if you have multiple Django instances running under the same +hostname. They can use different cookie paths, and each instance will only see +its own session cookie. + +SESSION_COOKIE_SECURE +--------------------- + +Default: ``False`` + +Whether to use a secure cookie for the session cookie. If this is set to +``True``, the cookie will be marked as "secure," which means browsers may +ensure that the cookie is only sent under an HTTPS connection. + +SESSION_EXPIRE_AT_BROWSER_CLOSE +------------------------------- + +Default: ``False`` + +Whether to expire the session when the user closes his or her browser. See +"Browser-length sessions vs. persistent sessions" above. + +SESSION_SAVE_EVERY_REQUEST +-------------------------- + +Default: ``False`` + +Whether to save the session data on every request. If this is ``False`` +(default), then the session data will only be saved if it has been modified -- +that is, if any of its dictionary values have been assigned or deleted. + +.. _Django settings: ../settings/ + +Technical details +================= + + * The session dictionary should accept any pickleable Python object. See + `the pickle module`_ for more information. + + * Session data is stored in a database table named ``django_session`` . + + * Django only sends a cookie if it needs to. If you don't set any session + data, it won't send a session cookie. + +.. _`the pickle module`: http://docs.python.org/library/pickle.html + +Session IDs in URLs +=================== + +The Django sessions framework is entirely, and solely, cookie-based. It does +not fall back to putting session IDs in URLs as a last resort, as PHP does. +This is an intentional design decision. Not only does that behavior make URLs +ugly, it makes your site vulnerable to session-ID theft via the "Referer" +header. diff --git a/parts/django/docs/topics/http/shortcuts.txt b/parts/django/docs/topics/http/shortcuts.txt new file mode 100644 index 0000000..315460e --- /dev/null +++ b/parts/django/docs/topics/http/shortcuts.txt @@ -0,0 +1,229 @@ +========================= +Django shortcut functions +========================= + +.. module:: django.shortcuts + :synopsis: + Convience shortcuts that spam multiple levels of Django's MVC stack. + +.. index:: shortcuts + +The package ``django.shortcuts`` collects helper functions and classes that +"span" multiple levels of MVC. In other words, these functions/classes +introduce controlled coupling for convenience's sake. + +``render_to_response`` +====================== + +.. function:: render_to_response(template[, dictionary][, context_instance][, mimetype]) + + Renders a given template with a given context dictionary and returns an + :class:`~django.http.HttpResponse` object with that rendered text. + +Required arguments +------------------ + +``template`` + The full name of a template to use or sequence of template names. If a + sequence is given, the first template that exists will be used. See the + :ref:`template loader documentation <ref-templates-api-the-python-api>` + for more information on how templates are found. + +Optional arguments +------------------ + +``dictionary`` + A dictionary of values to add to the template context. By default, this + is an empty dictionary. If a value in the dictionary is callable, the + view will call it just before rendering the template. + +``context_instance`` + The context instance to render the template with. By default, the template + will be rendered with a :class:`~django.template.Context` instance (filled + with values from ``dictionary``). If you need to use :ref:`context + processors <subclassing-context-requestcontext>`, render the template with + a :class:`~django.template.RequestContext` instance instead. Your code + might look something like this:: + + return render_to_response('my_template.html', + my_data_dictionary, + context_instance=RequestContext(request)) + +``mimetype`` + The MIME type to use for the resulting document. Defaults to the value of + the :setting:`DEFAULT_CONTENT_TYPE` setting. + +Example +------- + +The following example renders the template ``myapp/index.html`` with the +MIME type ``application/xhtml+xml``:: + + from django.shortcuts import render_to_response + + def my_view(request): + # View code here... + return render_to_response('myapp/index.html', {"foo": "bar"}, + mimetype="application/xhtml+xml") + +This example is equivalent to:: + + from django.http import HttpResponse + from django.template import Context, loader + + def my_view(request): + # View code here... + t = loader.get_template('myapp/template.html') + c = Context({'foo': 'bar'}) + return HttpResponse(t.render(c), + mimetype="application/xhtml+xml") + +``redirect`` +============ + +.. function:: redirect(to[, permanent=False], *args, **kwargs) + + .. versionadded:: 1.1 + + Returns an :class:`~django.http.HttpResponseRedirect` to the appropriate URL + for the arguments passed. + + The arguments could be: + + * A model: the model's `get_absolute_url()` function will be called. + + * A view name, possibly with arguments: `urlresolvers.reverse()` will + be used to reverse-resolve the name. + + * A URL, which will be used as-is for the redirect location. + + By default issues a temporary redirect; pass ``permanent=True`` to issue a + permanent redirect + +Examples +-------- + +You can use the :func:`redirect` function in a number of ways. + + 1. By passing some object; that object's + :meth:`~django.db.models.Model.get_absolute_url` method will be called + to figure out the redirect URL:: + + def my_view(request): + ... + object = MyModel.objects.get(...) + return redirect(object) + + 2. By passing the name of a view and optionally some positional or + keyword arguments; the URL will be reverse resolved using the + :func:`~django.core.urlresolvers.reverse` method:: + + def my_view(request): + ... + return redirect('some-view-name', foo='bar') + + 3. By passing a hardcoded URL to redirect to:: + + def my_view(request): + ... + return redirect('/some/url/') + + This also works with full URLs:: + + def my_view(request): + ... + return redirect('http://example.com/') + +By default, :func:`redirect` returns a temporary redirect. All of the above +forms accept a ``permanent`` argument; if set to ``True`` a permanent redirect +will be returned:: + + def my_view(request): + ... + object = MyModel.objects.get(...) + return redirect(object, permanent=True) + +``get_object_or_404`` +===================== + +.. function:: get_object_or_404(klass, *args, **kwargs) + + Calls :meth:`~django.db.models.QuerySet.get()` on a given model manager, + but it raises :class:`~django.http.Http404` instead of the model's + :class:`~django.core.exceptions.DoesNotExist` exception. + +Required arguments +------------------ + +``klass`` + A :class:`~django.db.models.Model`, :class:`~django.db.models.Manager` or + :class:`~django.db.models.QuerySet` instance from which to get the object. + +``**kwargs`` + Lookup parameters, which should be in the format accepted by ``get()`` and + ``filter()``. + +Example +------- + +The following example gets the object with the primary key of 1 from +``MyModel``:: + + from django.shortcuts import get_object_or_404 + + def my_view(request): + my_object = get_object_or_404(MyModel, pk=1) + +This example is equivalent to:: + + from django.http import Http404 + + def my_view(request): + try: + my_object = MyModel.objects.get(pk=1) + except MyModel.DoesNotExist: + raise Http404 + +Note: As with ``get()``, a +:class:`~django.core.exceptions.MultipleObjectsReturned` exception +will be raised if more than one object is found. + +``get_list_or_404`` +=================== + +.. function:: get_list_or_404(klass, *args, **kwargs) + + Returns the result of :meth:`~django.db.models.QuerySet.filter()` on a + given model manager, raising :class:`~django.http.Http404` if the resulting + list is empty. + +Required arguments +------------------ + +``klass`` + A :class:`~django.db.models.Model`, :class:`~django.db.models.Manager` or + :class:`~django.db.models.query.QuerySet` instance from which to get the + list. + +``**kwargs`` + Lookup parameters, which should be in the format accepted by ``get()`` and + ``filter()``. + +Example +------- + +The following example gets all published objects from ``MyModel``:: + + from django.shortcuts import get_list_or_404 + + def my_view(request): + my_objects = get_list_or_404(MyModel, published=True) + +This example is equivalent to:: + + from django.http import Http404 + + def my_view(request): + my_objects = list(MyModel.objects.filter(published=True)) + if not my_objects: + raise Http404 diff --git a/parts/django/docs/topics/http/urls.txt b/parts/django/docs/topics/http/urls.txt new file mode 100644 index 0000000..2361297 --- /dev/null +++ b/parts/django/docs/topics/http/urls.txt @@ -0,0 +1,890 @@ +============== +URL dispatcher +============== + +.. module:: django.core.urlresolvers + +A clean, elegant URL scheme is an important detail in a high-quality Web +application. Django lets you design URLs however you want, with no framework +limitations. + +There's no ``.php`` or ``.cgi`` required, and certainly none of that +``0,2097,1-1-1928,00`` nonsense. + +See `Cool URIs don't change`_, by World Wide Web creator Tim Berners-Lee, for +excellent arguments on why URLs should be clean and usable. + +.. _Cool URIs don't change: http://www.w3.org/Provider/Style/URI + +Overview +======== + +To design URLs for an app, you create a Python module informally called a +**URLconf** (URL configuration). This module is pure Python code and +is a simple mapping between URL patterns (as simple regular expressions) to +Python callback functions (your views). + +This mapping can be as short or as long as needed. It can reference other +mappings. And, because it's pure Python code, it can be constructed +dynamically. + +.. _how-django-processes-a-request: + +How Django processes a request +============================== + +When a user requests a page from your Django-powered site, this is the +algorithm the system follows to determine which Python code to execute: + + 1. Django determines the root URLconf module to use. Ordinarily, + this is the value of the :setting:`ROOT_URLCONF` setting, but if the incoming + ``HttpRequest`` object has an attribute called ``urlconf`` (set by + middleware :ref:`request processing <request-middleware>`), its value + will be used in place of the :setting:`ROOT_URLCONF` setting. + + 2. Django loads that Python module and looks for the variable + ``urlpatterns``. This should be a Python list, in the format returned by + the function :func:`django.conf.urls.defaults.patterns`. + + 3. Django runs through each URL pattern, in order, and stops at the first + one that matches the requested URL. + + 4. Once one of the regexes matches, Django imports and calls the given + view, which is a simple Python function. The view gets passed an + :class:`~django.http.HttpRequest` as its first argument and any values + captured in the regex as remaining arguments. + +Example +======= + +Here's a sample URLconf:: + + from django.conf.urls.defaults import * + + urlpatterns = patterns('', + (r'^articles/2003/$', 'news.views.special_case_2003'), + (r'^articles/(\d{4})/$', 'news.views.year_archive'), + (r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'), + (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'), + ) + +Notes: + + * ``from django.conf.urls.defaults import *`` makes the ``patterns()`` + function available. + + * To capture a value from the URL, just put parenthesis around it. + + * There's no need to add a leading slash, because every URL has that. For + example, it's ``^articles``, not ``^/articles``. + + * The ``'r'`` in front of each regular expression string is optional but + recommended. It tells Python that a string is "raw" -- that nothing in + the string should be escaped. See `Dive Into Python's explanation`_. + +Example requests: + + * A request to ``/articles/2005/03/`` would match the third entry in the + list. Django would call the function + ``news.views.month_archive(request, '2005', '03')``. + + * ``/articles/2005/3/`` would not match any URL patterns, because the + third entry in the list requires two digits for the month. + + * ``/articles/2003/`` would match the first pattern in the list, not the + second one, because the patterns are tested in order, and the first one + is the first test to pass. Feel free to exploit the ordering to insert + special cases like this. + + * ``/articles/2003`` would not match any of these patterns, because each + pattern requires that the URL end with a slash. + + * ``/articles/2003/03/3/`` would match the final pattern. Django would call + the function ``news.views.article_detail(request, '2003', '03', '3')``. + +.. _Dive Into Python's explanation: http://diveintopython.org/regular_expressions/street_addresses.html#re.matching.2.3 + +Named groups +============ + +The above example used simple, *non-named* regular-expression groups (via +parenthesis) to capture bits of the URL and pass them as *positional* arguments +to a view. In more advanced usage, it's possible to use *named* +regular-expression groups to capture URL bits and pass them as *keyword* +arguments to a view. + +In Python regular expressions, the syntax for named regular-expression groups +is ``(?P<name>pattern)``, where ``name`` is the name of the group and +``pattern`` is some pattern to match. + +Here's the above example URLconf, rewritten to use named groups:: + + urlpatterns = patterns('', + (r'^articles/2003/$', 'news.views.special_case_2003'), + (r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'), + (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'), + (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'news.views.article_detail'), + ) + +This accomplishes exactly the same thing as the previous example, with one +subtle difference: The captured values are passed to view functions as keyword +arguments rather than positional arguments. For example: + + * A request to ``/articles/2005/03/`` would call the function + ``news.views.month_archive(request, year='2005', month='03')``, instead + of ``news.views.month_archive(request, '2005', '03')``. + + * A request to ``/articles/2003/03/3/`` would call the function + ``news.views.article_detail(request, year='2003', month='03', day='3')``. + +In practice, this means your URLconfs are slightly more explicit and less prone +to argument-order bugs -- and you can reorder the arguments in your views' +function definitions. Of course, these benefits come at the cost of brevity; +some developers find the named-group syntax ugly and too verbose. + +The matching/grouping algorithm +------------------------------- + +Here's the algorithm the URLconf parser follows, with respect to named groups +vs. non-named groups in a regular expression: + +If there are any named arguments, it will use those, ignoring non-named arguments. +Otherwise, it will pass all non-named arguments as positional arguments. + +In both cases, it will pass any extra keyword arguments as keyword arguments. +See "Passing extra options to view functions" below. + +What the URLconf searches against +================================= + +The URLconf searches against the requested URL, as a normal Python string. This +does not include GET or POST parameters, or the domain name. + +For example, in a request to ``http://www.example.com/myapp/``, the URLconf +will look for ``myapp/``. + +In a request to ``http://www.example.com/myapp/?page=3``, the URLconf will look +for ``myapp/``. + +The URLconf doesn't look at the request method. In other words, all request +methods -- ``POST``, ``GET``, ``HEAD``, etc. -- will be routed to the same +function for the same URL. + +Syntax of the urlpatterns variable +================================== + +``urlpatterns`` should be a Python list, in the format returned by the function +:func:`django.conf.urls.defaults.patterns`. Always use ``patterns()`` to create +the ``urlpatterns`` variable. + +Convention is to use ``from django.conf.urls.defaults import *`` at the top of +your URLconf. This gives your module access to these objects: + +.. module:: django.conf.urls.defaults + +patterns +-------- + +.. function:: patterns(prefix, pattern_description, ...) + +A function that takes a prefix, and an arbitrary number of URL patterns, and +returns a list of URL patterns in the format Django needs. + +The first argument to ``patterns()`` is a string ``prefix``. See +`The view prefix`_ below. + +The remaining arguments should be tuples in this format:: + + (regular expression, Python callback function [, optional dictionary [, optional name]]) + +...where ``optional dictionary`` and ``optional name`` are optional. (See +`Passing extra options to view functions`_ below.) + +.. note:: + Because `patterns()` is a function call, it accepts a maximum of 255 + arguments (URL patterns, in this case). This is a limit for all Python + function calls. This is rarely a problem in practice, because you'll + typically structure your URL patterns modularly by using `include()` + sections. However, on the off-chance you do hit the 255-argument limit, + realize that `patterns()` returns a Python list, so you can split up the + construction of the list. + + :: + + urlpatterns = patterns('', + ... + ) + urlpatterns += patterns('', + ... + ) + + Python lists have unlimited size, so there's no limit to how many URL + patterns you can construct. The only limit is that you can only create 254 + at a time (the 255th argument is the initial prefix argument). + +url +--- + +.. versionadded:: 1.0 + +.. function:: url(regex, view, kwargs=None, name=None, prefix='') + +You can use the ``url()`` function, instead of a tuple, as an argument to +``patterns()``. This is convenient if you want to specify a name without the +optional extra arguments dictionary. For example:: + + urlpatterns = patterns('', + url(r'^index/$', index_view, name="main-view"), + ... + ) + +This function takes five arguments, most of which are optional:: + + url(regex, view, kwargs=None, name=None, prefix='') + +See `Naming URL patterns`_ for why the ``name`` parameter is useful. + +The ``prefix`` parameter has the same meaning as the first argument to +``patterns()`` and is only relevant when you're passing a string as the +``view`` parameter. + +handler404 +---------- + +.. data:: handler404 + +A callable, or a string representing the full Python import path to the view +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 +---------- + +.. data:: handler500 + +A callable, or a string representing the full Python import path to the view +that should be called in case of server errors. Server errors happen when you +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. + +include +------- + +.. function:: include(<module or pattern_list>) + +A function that takes a full Python import path to another URLconf module that +should be "included" in this place. + +.. versionadded:: 1.1 + +:func:`include` also accepts as an argument an iterable that returns URL +patterns. + +See `Including other URLconfs`_ below. + +Notes on capturing text in URLs +=============================== + +Each captured argument is sent to the view as a plain Python string, regardless +of what sort of match the regular expression makes. For example, in this +URLconf line:: + + (r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'), + +...the ``year`` argument to ``news.views.year_archive()`` will be a string, not +an integer, even though the ``\d{4}`` will only match integer strings. + +A convenient trick is to specify default parameters for your views' arguments. +Here's an example URLconf and view:: + + # URLconf + urlpatterns = patterns('', + (r'^blog/$', 'blog.views.page'), + (r'^blog/page(?P<num>\d+)/$', 'blog.views.page'), + ) + + # View (in blog/views.py) + def page(request, num="1"): + # Output the appropriate page of blog entries, according to num. + +In the above example, both URL patterns point to the same view -- +``blog.views.page`` -- but the first pattern doesn't capture anything from the +URL. If the first pattern matches, the ``page()`` function will use its +default argument for ``num``, ``"1"``. If the second pattern matches, +``page()`` will use whatever ``num`` value was captured by the regex. + +Performance +=========== + +Each regular expression in a ``urlpatterns`` is compiled the first time it's +accessed. This makes the system blazingly fast. + +The view prefix +=============== + +You can specify a common prefix in your ``patterns()`` call, to cut down on +code duplication. + +Here's the example URLconf from the :doc:`Django overview </intro/overview>`:: + + from django.conf.urls.defaults import * + + urlpatterns = patterns('', + (r'^articles/(\d{4})/$', 'news.views.year_archive'), + (r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'), + (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'), + ) + +In this example, each view has a common prefix -- ``'news.views'``. +Instead of typing that out for each entry in ``urlpatterns``, you can use the +first argument to the ``patterns()`` function to specify a prefix to apply to +each view function. + +With this in mind, the above example can be written more concisely as:: + + from django.conf.urls.defaults import * + + urlpatterns = patterns('news.views', + (r'^articles/(\d{4})/$', 'year_archive'), + (r'^articles/(\d{4})/(\d{2})/$', 'month_archive'), + (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'article_detail'), + ) + +Note that you don't put a trailing dot (``"."``) in the prefix. Django puts +that in automatically. + +Multiple view prefixes +---------------------- + +In practice, you'll probably end up mixing and matching views to the point +where the views in your ``urlpatterns`` won't have a common prefix. However, +you can still take advantage of the view prefix shortcut to remove duplication. +Just add multiple ``patterns()`` objects together, like this: + +Old:: + + from django.conf.urls.defaults import * + + urlpatterns = patterns('', + (r'^$', 'django.views.generic.date_based.archive_index'), + (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'django.views.generic.date_based.archive_month'), + (r'^tag/(?P<tag>\w+)/$', 'weblog.views.tag'), + ) + +New:: + + from django.conf.urls.defaults import * + + urlpatterns = patterns('django.views.generic.date_based', + (r'^$', 'archive_index'), + (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$','archive_month'), + ) + + urlpatterns += patterns('weblog.views', + (r'^tag/(?P<tag>\w+)/$', 'tag'), + ) + +Including other URLconfs +======================== + +At any point, your ``urlpatterns`` can "include" other URLconf modules. This +essentially "roots" a set of URLs below other ones. + +For example, here's the URLconf for the `Django Web site`_ itself. It includes a +number of other URLconfs:: + + from django.conf.urls.defaults import * + + urlpatterns = patterns('', + (r'^weblog/', include('django_website.apps.blog.urls.blog')), + (r'^documentation/', include('django_website.apps.docs.urls.docs')), + (r'^comments/', include('django.contrib.comments.urls')), + ) + +Note that the regular expressions in this example don't have a ``$`` +(end-of-string match character) but do include a trailing slash. Whenever +Django encounters ``include()``, it chops off whatever part of the URL matched +up to that point and sends the remaining string to the included URLconf for +further processing. + +.. versionadded:: 1.1 + +Another possibility is to include additional URL patterns not by specifying the +URLconf Python module defining them as the `include`_ argument but by using +directly the pattern list as returned by `patterns`_ instead. For example:: + + from django.conf.urls.defaults import * + + extra_patterns = patterns('', + url(r'reports/(?P<id>\d+)/$', 'credit.views.report', name='credit-reports'), + url(r'charge/$', 'credit.views.charge', name='credit-charge'), + ) + + urlpatterns = patterns('', + url(r'^$', 'apps.main.views.homepage', name='site-homepage'), + (r'^help/', include('apps.help.urls')), + (r'^credit/', include(extra_patterns)), + ) + +This approach can be seen in use when you deploy an instance of the Django +Admin application. The Django Admin is deployed as instances of a +:class:`~django.contrib.admin.AdminSite`; each +:class:`~django.contrib.admin.AdminSite` instance has an attribute ``urls`` +that returns the url patterns available to that instance. It is this attribute +that you ``include()`` into your projects ``urlpatterns`` when you deploy the +admin instance. + +.. _`Django Web site`: http://www.djangoproject.com/ + +Captured parameters +------------------- + +An included URLconf receives any captured parameters from parent URLconfs, so +the following example is valid:: + + # In settings/urls/main.py + urlpatterns = patterns('', + (r'^(?P<username>\w+)/blog/', include('foo.urls.blog')), + ) + + # In foo/urls/blog.py + urlpatterns = patterns('foo.views', + (r'^$', 'blog.index'), + (r'^archive/$', 'blog.archive'), + ) + +In the above example, the captured ``"username"`` variable is passed to the +included URLconf, as expected. + +.. _topics-http-defining-url-namespaces: + +Defining URL Namespaces +----------------------- + +When you need to deploy multiple instances of a single application, it can be +helpful to be able to differentiate between instances. This is especially +important when using :ref:`named URL patterns <naming-url-patterns>`, since +multiple instances of a single application will share named URLs. Namespaces +provide a way to tell these named URLs apart. + +A URL namespace comes in two parts, both of which are strings: + + * An **application namespace**. This describes the name of the application + that is being deployed. Every instance of a single application will have + the same application namespace. For example, Django's admin application + has the somewhat predictable application namespace of ``admin``. + + * An **instance namespace**. This identifies a specific instance of an + application. Instance namespaces should be unique across your entire + project. However, an instance namespace can be the same as the + application namespace. This is used to specify a default instance of an + application. For example, the default Django Admin instance has an + instance namespace of ``admin``. + +URL Namespaces can be specified in two ways. + +Firstly, you can provide the application and instance namespace as arguments +to ``include()`` when you construct your URL patterns. For example,:: + + (r'^help/', include('apps.help.urls', namespace='foo', app_name='bar')), + +This will include the URLs defined in ``apps.help.urls`` into the application +namespace ``bar``, with the instance namespace ``foo``. + +Secondly, you can include an object that contains embedded namespace data. If +you ``include()`` a ``patterns`` object, that object will be added to the +global namespace. However, you can also ``include()`` an object that contains +a 3-tuple containing:: + + (<patterns object>, <application namespace>, <instance namespace>) + +This will include the nominated URL patterns into the given application and +instance namespace. For example, the ``urls`` attribute of Django's +:class:`~django.contrib.admin.AdminSite` object returns a 3-tuple that contains +all the patterns in an admin site, plus the name of the admin instance, and the +application namespace ``admin``. + +Once you have defined namespaced URLs, you can reverse them. For details on +reversing namespaced urls, see the documentation on :ref:`reversing namespaced +URLs <topics-http-reversing-url-namespaces>`. + +Passing extra options to view functions +======================================= + +URLconfs have a hook that lets you pass extra arguments to your view functions, +as a Python dictionary. + +Any URLconf tuple can have an optional third element, which should be a +dictionary of extra keyword arguments to pass to the view function. + +For example:: + + urlpatterns = patterns('blog.views', + (r'^blog/(?P<year>\d{4})/$', 'year_archive', {'foo': 'bar'}), + ) + +In this example, for a request to ``/blog/2005/``, Django will call the +``blog.views.year_archive()`` view, passing it these keyword arguments:: + + year='2005', foo='bar' + +This technique is used in :doc:`generic views </ref/generic-views>` and in the +:doc:`syndication framework </ref/contrib/syndication>` to pass metadata and +options to views. + +.. admonition:: Dealing with conflicts + + It's possible to have a URL pattern which captures named keyword arguments, + and also passes arguments with the same names in its dictionary of extra + arguments. When this happens, the arguments in the dictionary will be used + instead of the arguments captured in the URL. + +Passing extra options to ``include()`` +-------------------------------------- + +Similarly, you can pass extra options to ``include()``. When you pass extra +options to ``include()``, *each* line in the included URLconf will be passed +the extra options. + +For example, these two URLconf sets are functionally identical: + +Set one:: + + # main.py + urlpatterns = patterns('', + (r'^blog/', include('inner'), {'blogid': 3}), + ) + + # inner.py + urlpatterns = patterns('', + (r'^archive/$', 'mysite.views.archive'), + (r'^about/$', 'mysite.views.about'), + ) + +Set two:: + + # main.py + urlpatterns = patterns('', + (r'^blog/', include('inner')), + ) + + # inner.py + urlpatterns = patterns('', + (r'^archive/$', 'mysite.views.archive', {'blogid': 3}), + (r'^about/$', 'mysite.views.about', {'blogid': 3}), + ) + +Note that extra options will *always* be passed to *every* line in the included +URLconf, regardless of whether the line's view actually accepts those options +as valid. For this reason, this technique is only useful if you're certain that +every view in the included URLconf accepts the extra options you're passing. + +Passing callable objects instead of strings +=========================================== + +Some developers find it more natural to pass the actual Python function object +rather than a string containing the path to its module. This alternative is +supported -- you can pass any callable object as the view. + +For example, given this URLconf in "string" notation:: + + urlpatterns = patterns('', + (r'^archive/$', 'mysite.views.archive'), + (r'^about/$', 'mysite.views.about'), + (r'^contact/$', 'mysite.views.contact'), + ) + +You can accomplish the same thing by passing objects rather than strings. Just +be sure to import the objects:: + + from mysite.views import archive, about, contact + + urlpatterns = patterns('', + (r'^archive/$', archive), + (r'^about/$', about), + (r'^contact/$', contact), + ) + +The following example is functionally identical. It's just a bit more compact +because it imports the module that contains the views, rather than importing +each view individually:: + + from mysite import views + + urlpatterns = patterns('', + (r'^archive/$', views.archive), + (r'^about/$', views.about), + (r'^contact/$', views.contact), + ) + +The style you use is up to you. + +Note that if you use this technique -- passing objects rather than strings -- +the view prefix (as explained in "The view prefix" above) will have no effect. + +.. _naming-url-patterns: + +Naming URL patterns +=================== + +.. versionadded:: 1.0 + +It's fairly common to use the same view function in multiple URL patterns in +your URLconf. For example, these two URL patterns both point to the ``archive`` +view:: + + urlpatterns = patterns('', + (r'^archive/(\d{4})/$', archive), + (r'^archive-summary/(\d{4})/$', archive, {'summary': True}), + ) + +This is completely valid, but it leads to problems when you try to do reverse +URL matching (through the ``permalink()`` decorator or the :ttag:`url` template +tag). Continuing this example, if you wanted to retrieve the URL for the +``archive`` view, Django's reverse URL matcher would get confused, because *two* +URLpatterns point at that view. + +To solve this problem, Django supports **named URL patterns**. That is, you can +give a name to a URL pattern in order to distinguish it from other patterns +using the same view and parameters. Then, you can use this name in reverse URL +matching. + +Here's the above example, rewritten to use named URL patterns:: + + urlpatterns = patterns('', + url(r'^archive/(\d{4})/$', archive, name="full-archive"), + url(r'^archive-summary/(\d{4})/$', archive, {'summary': True}, "arch-summary"), + ) + +With these names in place (``full-archive`` and ``arch-summary``), you can +target each pattern individually by using its name: + +.. code-block:: html+django + + {% 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. + +The string used for the URL name can contain any characters you like. You are +not restricted to valid Python names. + +.. note:: + + When you name your URL patterns, make sure you use names that are unlikely + to clash with any other application's choice of names. If you call your URL + pattern ``comment``, and another application does the same thing, there's + no guarantee which URL will be inserted into your template when you use + this name. + + Putting a prefix on your URL names, perhaps derived from the application + name, will decrease the chances of collision. We recommend something like + ``myapp-comment`` instead of ``comment``. + +.. _topics-http-reversing-url-namespaces: + +URL namespaces +-------------- + +.. versionadded:: 1.1 + +Namespaced URLs are specified using the ``:`` operator. For example, the main +index page of the admin application is referenced using ``admin:index``. This +indicates a namespace of ``admin``, and a named URL of ``index``. + +Namespaces can also be nested. The named URL ``foo:bar:whiz`` would look for +a pattern named ``whiz`` in the namespace ``bar`` that is itself defined within +the top-level namespace ``foo``. + +When given a namespaced URL (e.g. ``myapp:index``) to resolve, Django splits +the fully qualified name into parts, and then tries the following lookup: + + 1. First, Django looks for a matching application namespace (in this + example, ``myapp``). This will yield a list of instances of that + application. + + 2. If there is a *current* application defined, Django finds and returns + the URL resolver for that instance. The *current* application can be + specified as an attribute on the template context - applications that + expect to have multiple deployments should set the ``current_app`` + attribute on any ``Context`` or ``RequestContext`` that is used to + render a template. + + The current application can also be specified manually as an argument + to the :func:`reverse()` function. + + 3. If there is no current application. Django looks for a default + application instance. The default application instance is the instance + that has an instance namespace matching the application namespace (in + this example, an instance of the ``myapp`` called ``myapp``). + + 4. If there is no default application instance, Django will pick the last + deployed instance of the application, whatever its instance name may be. + + 5. If the provided namespace doesn't match an application namespace in + step 1, Django will attempt a direct lookup of the namespace as an + instance namespace. + +If there are nested namespaces, these steps are repeated for each part of the +namespace until only the view name is unresolved. The view name will then be +resolved into a URL in the namespace that has been found. + +To show this resolution strategy in action, consider an example of two instances +of ``myapp``: one called ``foo``, and one called ``bar``. ``myapp`` has a main +index page with a URL named `index`. Using this setup, the following lookups are +possible: + + * If one of the instances is current - say, if we were rendering a utility page + in the instance ``bar`` - ``myapp:index`` will resolve to the index page of + the instance ``bar``. + + * If there is no current instance - say, if we were rendering a page + somewhere else on the site - ``myapp:index`` will resolve to the last + registered instance of ``myapp``. Since there is no default instance, + the last instance of ``myapp`` that is registered will be used. This could + be ``foo`` or ``bar``, depending on the order they are introduced into the + urlpatterns of the project. + + * ``foo:index`` will always resolve to the index page of the instance ``foo``. + +If there was also a default instance - i.e., an instance named `myapp` - the +following would happen: + + * If one of the instances is current - say, if we were rendering a utility page + in the instance ``bar`` - ``myapp:index`` will resolve to the index page of + the instance ``bar``. + + * If there is no current instance - say, if we were rendering a page somewhere + else on the site - ``myapp:index`` will resolve to the index page of the + default instance. + + * ``foo:index`` will again resolve to the index page of the instance ``foo``. + + +Utility methods +=============== + +reverse() +--------- + +If you need to use something similar to the :ttag:`url` template tag in +your code, Django provides the following method (in the +``django.core.urlresolvers`` module): + +.. function:: reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None) + +``viewname`` is either the function name (either a function reference, or the +string version of the name, if you used that form in ``urlpatterns``) or the +`URL pattern name`_. Normally, you won't need to worry about the +``urlconf`` parameter and will only pass in the positional and keyword +arguments to use in the URL matching. For example:: + + from django.core.urlresolvers import reverse + + def myview(request): + return HttpResponseRedirect(reverse('arch-summary', args=[1945])) + +.. _URL pattern name: `Naming URL patterns`_ + +The ``reverse()`` function can reverse a large variety of regular expression +patterns for URLs, but not every possible one. The main restriction at the +moment is that the pattern cannot contain alternative choices using the +vertical bar (``"|"``) character. You can quite happily use such patterns for +matching against incoming URLs and sending them off to views, but you cannot +reverse such patterns. + +.. versionadded:: 1.1 + +The ``current_app`` argument allows you to provide a hint to the resolver +indicating the application to which the currently executing view belongs. +This ``current_app`` argument is used as a hint to resolve application +namespaces into URLs on specific application instances, according to the +:ref:`namespaced URL resolution strategy <topics-http-reversing-url-namespaces>`. + +.. admonition:: Make sure your views are all correct. + + As part of working out which URL names map to which patterns, the + ``reverse()`` function has to import all of your URLconf files and examine + the name of each view. This involves importing each view function. If + there are *any* errors whilst importing any of your view functions, it + will cause ``reverse()`` to raise an error, even if that view function is + not the one you are trying to reverse. + + Make sure that any views you reference in your URLconf files exist and can + be imported correctly. Do not include lines that reference views you + haven't written yet, because those views will not be importable. + +resolve() +--------- + +The :func:`django.core.urlresolvers.resolve` function can be used for resolving +URL paths to the corresponding view functions. It has the following signature: + +.. function:: resolve(path, urlconf=None) + +``path`` is the URL path you want to resolve. As with +:func:`~django.core.urlresolvers.reverse`, you don't need to +worry about the ``urlconf`` parameter. The function returns +the triple (view function, arguments, keyword arguments). + +If the URL does not resolve, the function raises an +:class:`~django.http.Http404` exception. + +For example, it can be used for testing if a view would raise a ``Http404`` +error before redirecting to it:: + + from urlparse import urlparse + from django.core.urlresolvers import resolve + from django.http import HttpResponseRedirect, Http404 + + def myview(request): + next = request.META.get('HTTP_REFERER', None) or '/' + response = HttpResponseRedirect(next) + + # modify the request and response as required, e.g. change locale + # and set corresponding locale cookie + + view, args, kwargs = resolve(urlparse(next)[2]) + kwargs['request'] = request + try: + view(*args, **kwargs) + except Http404: + return HttpResponseRedirect('/') + return response + +permalink() +----------- + +The :func:`django.db.models.permalink` decorator is useful for writing short +methods that return a full URL path. For example, a model's +``get_absolute_url()`` method. See :func:`django.db.models.permalink` for more. + +get_script_prefix() +------------------- + +.. function:: get_script_prefix() + +.. versionadded:: 1.0 + +Normally, you should always use :func:`~django.core.urlresolvers.reverse` or +:func:`~django.db.models.permalink` to define URLs within your application. +However, if your application constructs part of the URL hierarchy itself, you +may occasionally need to generate URLs. In that case, you need to be able to +find the base URL of the Django project within its web server +(normally, :func:`~django.core.urlresolvers.reverse` takes care of this for +you). In that case, you can call ``get_script_prefix()``, which will return the +script prefix portion of the URL for your Django project. If your Django +project is at the root of its webserver, this is always ``"/"``, but it can be +changed, for instance by using ``django.root`` (see :ref:`How to use +Django with Apache and mod_python <howto-deployment-modpython>`).
\ No newline at end of file diff --git a/parts/django/docs/topics/http/views.txt b/parts/django/docs/topics/http/views.txt new file mode 100644 index 0000000..2818f42 --- /dev/null +++ b/parts/django/docs/topics/http/views.txt @@ -0,0 +1,202 @@ +============= +Writing Views +============= + +A view function, or *view* for short, is simply a Python function that takes a +Web request and returns a Web response. This response can be the HTML contents +of a Web page, or a redirect, or a 404 error, or an XML document, or an image . +. . or anything, really. The view itself contains whatever arbitrary logic is +necessary to return that response. This code can live anywhere you want, as long +as it's on your Python path. There's no other requirement--no "magic," so to +speak. For the sake of putting the code *somewhere*, let's create a file called +``views.py`` in the ``mysite`` directory, which you created in the previous +chapter. + +A simple view +============= + +Here's a view that returns the current date and time, as an HTML document: + +.. code-block:: python + + from django.http import HttpResponse + import datetime + + def current_datetime(request): + now = datetime.datetime.now() + html = "<html><body>It is now %s.</body></html>" % now + return HttpResponse(html) + +Let's step through this code one line at a time: + + * First, we import the class :class:`~django.http.HttpResponse` from the + :mod:`django.http` module, along with Python's ``datetime`` library. + + * Next, we define a function called ``current_datetime``. This is the view + function. Each view function takes an :class:`~django.http.HttpRequest` + object as its first parameter, which is typically named ``request``. + + Note that the name of the view function doesn't matter; it doesn't have to + be named in a certain way in order for Django to recognize it. We're + calling it ``current_datetime`` here, because that name clearly indicates + what it does. + + * The view returns an :class:`~django.http.HttpResponse` object that + contains the generated response. Each view function is responsible for + returning an :class:`~django.http.HttpResponse` object. (There are + exceptions, but we'll get to those later.) + +.. admonition:: Django's Time Zone + + Django includes a ``TIME_ZONE`` setting that defaults to + ``America/Chicago``. This probably isn't where you live, so you might want + to change it in your settings file. + +Mapping URLs to Views +===================== + +So, to recap, this view function returns an HTML page that includes the current +date and time. To display this view at a particular URL, you'll need to create a +*URLconf*; see :doc:`/topics/http/urls` for instructions. + +Returning errors +================ + +Returning HTTP error codes in Django is easy. There are subclasses of +:class:`~django.http.HttpResponse` for a number of common HTTP status codes +other than 200 (which means *"OK"*). You can find the full list of available +subclasses in the :ref:`request/response <ref-httpresponse-subclasses>` +documentation. Just return an instance of one of those subclasses instead of +a normal :class:`~django.http.HttpResponse` in order to signify an error. For +example:: + + def my_view(request): + # ... + if foo: + return HttpResponseNotFound('<h1>Page not found</h1>') + else: + return HttpResponse('<h1>Page was found</h1>') + +There isn't a specialized subclass for every possible HTTP response code, +since many of them aren't going to be that common. However, as documented in +the :class:`~django.http.HttpResponse` documentation, you can also pass the +HTTP status code into the constructor for :class:`~django.http.HttpResponse` +to create a return class for any status code you like. For example:: + + def my_view(request): + # ... + + # Return a "created" (201) response code. + return HttpResponse(status=201) + +Because 404 errors are by far the most common HTTP error, there's an easier way +to handle those errors. + +The Http404 exception +--------------------- + +.. class:: django.http.Http404() + +When you return an error such as :class:`~django.http.HttpResponseNotFound`, +you're responsible for defining the HTML of the resulting error page:: + + return HttpResponseNotFound('<h1>Page not found</h1>') + +For convenience, and because it's a good idea to have a consistent 404 error page +across your site, Django provides an ``Http404`` exception. If you raise +``Http404`` at any point in a view function, Django will catch it and return the +standard error page for your application, along with an HTTP error code 404. + +Example usage:: + + from django.http import Http404 + + def detail(request, poll_id): + try: + p = Poll.objects.get(pk=poll_id) + except Poll.DoesNotExist: + raise Http404 + return render_to_response('polls/detail.html', {'poll': p}) + +In order to use the ``Http404`` exception to its fullest, you should create a +template that is displayed when a 404 error is raised. This template should be +called ``404.html`` and located in the top level of your template tree. + +Customizing error views +======================= + +The 404 (page not found) view +----------------------------- + +When you raise an ``Http404`` exception, Django loads a special view devoted +to handling 404 errors. By default, it's the view +``django.views.defaults.page_not_found``, which loads and renders the template +``404.html``. + +This means you need to define a ``404.html`` template in your root template +directory. This template will be used for all 404 errors. + +This ``page_not_found`` view should suffice for 99% of Web applications, but if +you want to override the 404 view, you can specify ``handler404`` in your +URLconf, like so:: + + handler404 = 'mysite.views.my_custom_404_view' + +Behind the scenes, Django determines the 404 view by looking for ``handler404``. +By default, URLconfs contain the following line:: + + from django.conf.urls.defaults import * + +That takes care of setting ``handler404`` in the current module. As you can see +in ``django/conf/urls/defaults.py``, ``handler404`` is set to +``'django.views.defaults.page_not_found'`` by default. + +Three things to note about 404 views: + + * The 404 view is also called if Django doesn't find a match after checking + every regular expression in the URLconf. + + * If you don't define your own 404 view -- and simply use the + default, which is recommended -- you still have one obligation: + you must create a ``404.html`` template in the root of your + template directory. The default 404 view will use that template + for all 404 errors. The default 404 view will pass one variable + to the template: ``request_path``, which is the URL that resulted + in the 404. + + * The 404 view is passed a :class:`~django.template.RequestContext` and + will have access to variables supplied by your + :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting (e.g., + :setting:`MEDIA_URL`). + + * If :setting:`DEBUG` is set to ``True`` (in your settings module), then + your 404 view will never be used, and the traceback will be displayed + instead. + +The 500 (server error) view +---------------------------- + +Similarly, Django executes special-case behavior in the case of runtime errors +in view code. If a view results in an exception, Django will, by default, call +the view ``django.views.defaults.server_error``, which loads and renders the +template ``500.html``. + +This means you need to define a ``500.html`` template in your root template +directory. This template will be used for all server errors. The default 500 +view passes no variables to this template and is rendered with an empty +``Context`` to lessen the chance of additional errors. + +This ``server_error`` view should suffice for 99% of Web applications, but if +you want to override the view, you can specify ``handler500`` in your +URLconf, like so:: + + handler500 = 'mysite.views.my_custom_error_view' + +Behind the scenes, Django determines the error view by looking for ``handler500``. +By default, URLconfs contain the following line:: + + from django.conf.urls.defaults import * + +That takes care of setting ``handler500`` in the current module. As you can see +in ``django/conf/urls/defaults.py``, ``handler500`` is set to +``'django.views.defaults.server_error'`` by default. diff --git a/parts/django/docs/topics/i18n/deployment.txt b/parts/django/docs/topics/i18n/deployment.txt new file mode 100644 index 0000000..4727841 --- /dev/null +++ b/parts/django/docs/topics/i18n/deployment.txt @@ -0,0 +1,191 @@ +========================== +Deployment of translations +========================== + +If you don't need internationalization +====================================== + +Django's internationalization hooks are on by default, and that means there's a +bit of i18n-related overhead in certain places of the framework. If you don't +use internationalization, you should take the two seconds to set +:setting:`USE_I18N = False <USE_I18N>` in your settings file. If +:setting:`USE_I18N` is set to ``False``, then Django will make some +optimizations so as not to load the internationalization machinery. + +You'll probably also want to remove ``'django.core.context_processors.i18n'`` +from your ``TEMPLATE_CONTEXT_PROCESSORS`` setting. + +.. note:: + + There is also an independent but related :setting:`USE_L10N` setting that + controls if Django should implement format localization. + + If :setting:`USE_L10N` is set to ``True``, Django will handle numbers times, + and dates in the format of the current locale. That includes representation + of these field types on templates and allowed input formats for dates, + times on model forms. + + See :ref:`format-localization` for more details. + +If you do need internationalization +=================================== + +.. _how-django-discovers-language-preference: + +How Django discovers language preference +---------------------------------------- + +Once you've prepared your translations -- or, if you just want to use the +translations that come with Django -- you'll just need to activate translation +for your app. + +Behind the scenes, Django has a very flexible model of deciding which language +should be used -- installation-wide, for a particular user, or both. + +To set an installation-wide language preference, set :setting:`LANGUAGE_CODE`. +Django uses this language as the default translation -- the final attempt if no +other translator finds a translation. + +If all you want to do is run Django with your native language, and a language +file is available for it, all you need to do is set ``LANGUAGE_CODE``. + +If you want to let each individual user specify which language he or she +prefers, use ``LocaleMiddleware``. ``LocaleMiddleware`` enables language +selection based on data from the request. It customizes content for each user. + +To use ``LocaleMiddleware``, add ``'django.middleware.locale.LocaleMiddleware'`` +to your ``MIDDLEWARE_CLASSES`` setting. Because middleware order matters, you +should follow these guidelines: + + * Make sure it's one of the first middlewares installed. + * It should come after ``SessionMiddleware``, because ``LocaleMiddleware`` + makes use of session data. + * If you use ``CacheMiddleware``, put ``LocaleMiddleware`` after it. + +For example, your ``MIDDLEWARE_CLASSES`` might look like this:: + + MIDDLEWARE_CLASSES = ( + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', + 'django.middleware.common.CommonMiddleware', + ) + +(For more on middleware, see the :doc:`middleware documentation +</topics/http/middleware>`.) + +``LocaleMiddleware`` tries to determine the user's language preference by +following this algorithm: + + * First, it looks for a ``django_language`` key in the current user's + session. + + * Failing that, it looks for a cookie. + + .. versionchanged:: 1.0 + + In Django version 0.96 and before, the cookie's name is hard-coded to + ``django_language``. In Django 1,0, The cookie name is set by the + ``LANGUAGE_COOKIE_NAME`` setting. (The default name is + ``django_language``.) + + * Failing that, it looks at the ``Accept-Language`` HTTP header. This + header is sent by your browser and tells the server which language(s) you + prefer, in order by priority. Django tries each language in the header + until it finds one with available translations. + + * Failing that, it uses the global ``LANGUAGE_CODE`` setting. + +.. _locale-middleware-notes: + +Notes: + + * In each of these places, the language preference is expected to be in the + standard :term:`language format<language code>`, as a string. For example, + Brazilian Portuguese is ``pt-br``. + + * If a base language is available but the sublanguage specified is not, + Django uses the base language. For example, if a user specifies ``de-at`` + (Austrian German) but Django only has ``de`` available, Django uses + ``de``. + + * Only languages listed in the :setting:`LANGUAGES` setting can be selected. + If you want to restrict the language selection to a subset of provided + languages (because your application doesn't provide all those languages), + set ``LANGUAGES`` to a list of languages. For example:: + + LANGUAGES = ( + ('de', _('German')), + ('en', _('English')), + ) + + This example restricts languages that are available for automatic + selection to German and English (and any sublanguage, like de-ch or + en-us). + + * If you define a custom ``LANGUAGES`` setting, as explained in the + previous bullet, it's OK to mark the languages as translation strings + -- but use a "dummy" ``ugettext()`` function, not the one in + ``django.utils.translation``. You should *never* import + ``django.utils.translation`` from within your settings file, because that + module in itself depends on the settings, and that would cause a circular + import. + + The solution is to use a "dummy" ``ugettext()`` function. Here's a sample + settings file:: + + ugettext = lambda s: s + + LANGUAGES = ( + ('de', ugettext('German')), + ('en', ugettext('English')), + ) + + With this arrangement, ``django-admin.py makemessages`` will still find + and mark these strings for translation, but the translation won't happen + at runtime -- so you'll have to remember to wrap the languages in the + *real* ``ugettext()`` in any code that uses ``LANGUAGES`` at runtime. + + * The ``LocaleMiddleware`` can only select languages for which there is a + Django-provided base translation. If you want to provide translations + for your application that aren't already in the set of translations + in Django's source tree, you'll want to provide at least a basic + one as described in the :ref:`Locale restrictions<locale-restrictions>` + note. + +Once ``LocaleMiddleware`` determines the user's preference, it makes this +preference available as ``request.LANGUAGE_CODE`` for each +:class:`~django.http.HttpRequest`. Feel free to read this value in your view +code. Here's a simple example:: + + def hello_world(request, count): + if request.LANGUAGE_CODE == 'de-at': + return HttpResponse("You prefer to read Austrian German.") + else: + return HttpResponse("You prefer to read another language.") + +Note that, with static (middleware-less) translation, the language is in +``settings.LANGUAGE_CODE``, while with dynamic (middleware) translation, it's +in ``request.LANGUAGE_CODE``. + +.. _settings file: ../settings/ +.. _middleware documentation: ../middleware/ +.. _session: ../sessions/ +.. _request object: ../request_response/#httprequest-objects + +How Django discovers translations +--------------------------------- + +As described in :ref:`using-translations-in-your-own-projects`, +at runtime, Django looks for translations by following this algorithm: + + * First, it looks for a ``locale`` directory in the directory containing + your settings file. + * Second, it looks for a ``locale`` directory in the project directory. + * Third, it looks for a ``locale`` directory in each of the installed apps. + It does this in the reverse order of INSTALLED_APPS + * Finally, it checks the Django-provided base translation in + ``django/conf/locale``. + +In all cases the name of the directory containing the translation is expected to +be named using :term:`locale name` notation. E.g. ``de``, ``pt_BR``, ``es_AR``, +etc. diff --git a/parts/django/docs/topics/i18n/index.txt b/parts/django/docs/topics/i18n/index.txt new file mode 100644 index 0000000..9c25192 --- /dev/null +++ b/parts/django/docs/topics/i18n/index.txt @@ -0,0 +1,113 @@ +===================================== +Internationalization and localization +===================================== + +Overview +======== + +Django has full support for internationalization of text in code and +templates, and format localization of dates and numbers. Here's how it works. + +Essentially, Django does two things: + + * It allows developers and template authors to specify which parts of + their apps should be translatable. + * It uses these hooks to translate Web apps for particular users according + to their language preferences. + +The complete process can be seen as divided in three stages. It is also possible +to identify an identical number of roles with very well defined responsibilities +associated with each of these tasks (although it's perfectly normal if you +find yourself performing more than one of these roles): + + * For application authors wishing to make sure their Django apps can be + used in different locales: :doc:`/topics/i18n/internationalization`. + * For translators wanting to translate Django apps: :doc:`/topics/i18n/localization`. + * For system administrators/final users setting up internationalized apps or + developers integrating third party apps: :doc:`/topics/i18n/deployment`. + +.. toctree:: + :hidden: + :maxdepth: 1 + + internationalization + localization + deployment + +.. _ seealso:: + +For more general information about the topic, see the `GNU gettext documentation`_ +and the `Wikipedia article`_. + +.. _GNU gettext documentation: http://www.gnu.org/software/gettext/manual/gettext.html#Concepts +.. _Wikipedia article: http://en.wikipedia.org/wiki/Internationalization_and_localization + +Glossary +======== + +First lets define some terms that will help us to handle a common language: + +.. glossary:: + + locale name + A locale name, either a language specification of the form ``ll`` or a + combined language and country specification of the form ``ll_CC``. + Examples: ``it``, ``de_AT``, ``es``, ``pt_BR``. Note the underscore in + some of them and the case of the part located to its right. + + language code + Represents the name of a language. Browsers send the names of the + languages they accept in the ``Accept-Language`` HTTP header using this + format. Examples: ``it``, ``de-at``, ``es``, ``pt-br``. Note the ``-`` + separator. + + message file + A message file is a plain-text file, representing a single language, + that contains all available :term:`translation strings + <translation string>` and how they should be represented in the given + language. Message files have a ``.po`` file extension. + + translation string + A literal that can be translated. + +.. _specialties-of-django-i18n: + +Specialties of Django translation +================================= + +Django's translation machinery uses the standard ``gettext`` module that comes +with Python. If you know ``gettext``, you might note these specialties in the +way Django does translation: + + * The string domain is ``django`` or ``djangojs``. This string domain is + used to differentiate between different programs that store their data + in a common message-file library (usually ``/usr/share/locale/``). The + ``django`` domain is used for python and template translation strings + and is loaded into the global translation catalogs. The ``djangojs`` + domain is only used for JavaScript translation catalogs to make sure + that those are as small as possible. + * Django doesn't use ``xgettext`` alone. It uses Python wrappers around + ``xgettext`` and ``msgfmt``. This is mostly for convenience. + +.. _technical-messages: + +Django technical message IDs +---------------------------- + +.. versionchanged:: 1.2 + Starting with Django 1.2, technical message IDs are being replaced by :ref:`format-localization` + +Django uses technical message IDs to translate date formats and time formats. +Technical message IDs are :term:`translation strings <translation string>` and +can be easily recognized; they're all upper case. You don't translate the +message ID as with other translation strings, you provide the correct local +variant on the provided English value. The format is identical to the format +strings used by the ``now`` template tag. + +For example, with ``DATETIME_FORMAT`` (or ``DATE_FORMAT`` or ``TIME_FORMAT``), +this would be the format string that you want to use in your language. A Django +contributor localizing it to Spanish probably would provide a ``"j N Y P"`` +"translation" for it in the relevant ``django.po`` file:: + + msgid "DATETIME_FORMAT" + msgstr "j N Y P" diff --git a/parts/django/docs/topics/i18n/internationalization.txt b/parts/django/docs/topics/i18n/internationalization.txt new file mode 100644 index 0000000..b6847ea --- /dev/null +++ b/parts/django/docs/topics/i18n/internationalization.txt @@ -0,0 +1,624 @@ +==================== +Internationalization +==================== + +Overview +======== + +The goal of internationalization is to allow a single Web application to offer +its content and functionality in multiple languages and locales. + +For text translations, you, the Django developer, can accomplish this goal by +adding a minimal amount of hooks to your Python and templates. These hooks +are called **translation strings**. They tell Django: "This text should be +translated into the end user's language, if a translation for this text is +available in that language." It's your responsibility to mark translatable +strings; the system can only translate strings it knows about. + +Django takes care of using these hooks to translate Web apps, on the fly, +according to users' language preferences. + +Specifying translation strings: In Python code +============================================== + +Standard translation +-------------------- + +Specify a translation string by using the function ``ugettext()``. It's +convention to import this as a shorter alias, ``_``, to save typing. + +.. note:: + Python's standard library ``gettext`` module installs ``_()`` into the + global namespace, as an alias for ``gettext()``. In Django, we have chosen + not to follow this practice, for a couple of reasons: + + 1. For international character set (Unicode) support, ``ugettext()`` is + more useful than ``gettext()``. Sometimes, you should be using + ``ugettext_lazy()`` as the default translation method for a particular + file. Without ``_()`` in the global namespace, the developer has to + think about which is the most appropriate translation function. + + 2. The underscore character (``_``) is used to represent "the previous + result" in Python's interactive shell and doctest tests. Installing a + global ``_()`` function causes interference. Explicitly importing + ``ugettext()`` as ``_()`` avoids this problem. + +.. highlightlang:: python + +In this example, the text ``"Welcome to my site."`` is marked as a translation +string:: + + from django.utils.translation import ugettext as _ + + def my_view(request): + output = _("Welcome to my site.") + return HttpResponse(output) + +Obviously, you could code this without using the alias. This example is +identical to the previous one:: + + from django.utils.translation import ugettext + + def my_view(request): + output = ugettext("Welcome to my site.") + return HttpResponse(output) + +Translation works on computed values. This example is identical to the previous +two:: + + def my_view(request): + words = ['Welcome', 'to', 'my', 'site.'] + output = _(' '.join(words)) + return HttpResponse(output) + +Translation works on variables. Again, here's an identical example:: + + def my_view(request): + sentence = 'Welcome to my site.' + output = _(sentence) + return HttpResponse(output) + +(The caveat with using variables or computed values, as in the previous two +examples, is that Django's translation-string-detecting utility, +``django-admin.py makemessages``, won't be able to find these strings. More on +``makemessages`` later.) + +The strings you pass to ``_()`` or ``ugettext()`` can take placeholders, +specified with Python's standard named-string interpolation syntax. Example:: + + def my_view(request, m, d): + output = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d} + return HttpResponse(output) + +This technique lets language-specific translations reorder the placeholder +text. For example, an English translation may be ``"Today is November 26."``, +while a Spanish translation may be ``"Hoy es 26 de Noviembre."`` -- with the +the month and the day placeholders swapped. + +For this reason, you should use named-string interpolation (e.g., ``%(day)s``) +instead of positional interpolation (e.g., ``%s`` or ``%d``) whenever you +have more than a single parameter. If you used positional interpolation, +translations wouldn't be able to reorder placeholder text. + +Marking strings as no-op +------------------------ + +Use the function ``django.utils.translation.ugettext_noop()`` to mark a string +as a translation string without translating it. The string is later translated +from a variable. + +Use this if you have constant strings that should be stored in the source +language because they are exchanged over systems or users -- such as strings in +a database -- but should be translated at the last possible point in time, such +as when the string is presented to the user. + +Pluralization +------------- + +Use the function ``django.utils.translation.ungettext()`` to specify pluralized +messages. + +``ungettext`` takes three arguments: the singular translation string, the plural +translation string and the number of objects. + +This function is useful when you need your Django application to be localizable +to languages where the number and complexity of `plural forms +<http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms>`_ is +greater than the two forms used in English ('object' for the singular and +'objects' for all the cases where ``count`` is different from zero, irrespective +of its value.) + +For example:: + + from django.utils.translation import ungettext + def hello_world(request, count): + page = ungettext('there is %(count)d object', 'there are %(count)d objects', count) % { + 'count': count, + } + return HttpResponse(page) + +In this example the number of objects is passed to the translation languages as +the ``count`` variable. + +Lets see a slightly more complex usage example:: + + from django.utils.translation import ungettext + + count = Report.objects.count() + if count == 1: + name = Report._meta.verbose_name + else: + name = Report._meta.verbose_name_plural + + text = ungettext( + 'There is %(count)d %(name)s available.', + 'There are %(count)d %(name)s available.', + count + ) % { + 'count': count, + 'name': name + } + +Here we reuse localizable, hopefully already translated literals (contained in +the ``verbose_name`` and ``verbose_name_plural`` model ``Meta`` options) for +other parts of the sentence so all of it is consistently based on the +cardinality of the elements at play. + +.. _pluralization-var-notes: + +.. note:: + + When using this technique, make sure you use a single name for every + extrapolated variable included in the literal. In the example above note how + we used the ``name`` Python variable in both translation strings. This + example would fail:: + + from django.utils.translation import ungettext + from myapp.models import Report + + count = Report.objects.count() + d = { + 'count': count, + 'name': Report._meta.verbose_name, + 'plural_name': Report._meta.verbose_name_plural + } + text = ungettext( + 'There is %(count)d %(name)s available.', + 'There are %(count)d %(plural_name)s available.', + count + ) % d + + You would get a ``a format specification for argument 'name', as in + 'msgstr[0]', doesn't exist in 'msgid'`` error when running + ``django-admin.py compilemessages``. + +.. _lazy-translations: + +Lazy translation +---------------- + +Use the function ``django.utils.translation.ugettext_lazy()`` to translate +strings lazily -- when the value is accessed rather than when the +``ugettext_lazy()`` function is called. + +For example, to translate a model's ``help_text``, do the following:: + + from django.utils.translation import ugettext_lazy + + class MyThing(models.Model): + name = models.CharField(help_text=ugettext_lazy('This is the help text')) + +In this example, ``ugettext_lazy()`` stores a lazy reference to the string -- +not the actual translation. The translation itself will be done when the string +is used in a string context, such as template rendering on the Django admin +site. + +The result of a ``ugettext_lazy()`` call can be used wherever you would use a +unicode string (an object with type ``unicode``) in Python. If you try to use +it where a bytestring (a ``str`` object) is expected, things will not work as +expected, since a ``ugettext_lazy()`` object doesn't know how to convert +itself to a bytestring. You can't use a unicode string inside a bytestring, +either, so this is consistent with normal Python behavior. For example:: + + # This is fine: putting a unicode proxy into a unicode string. + u"Hello %s" % ugettext_lazy("people") + + # This will not work, since you cannot insert a unicode object + # into a bytestring (nor can you insert our unicode proxy there) + "Hello %s" % ugettext_lazy("people") + +If you ever see output that looks like ``"hello +<django.utils.functional...>"``, you have tried to insert the result of +``ugettext_lazy()`` into a bytestring. That's a bug in your code. + +If you don't like the verbose name ``ugettext_lazy``, you can just alias it as +``_`` (underscore), like so:: + + from django.utils.translation import ugettext_lazy as _ + + class MyThing(models.Model): + name = models.CharField(help_text=_('This is the help text')) + +Always use lazy translations in :doc:`Django models </topics/db/models>`. +Field names and table names should be marked for translation (otherwise, they +won't be translated in the admin interface). This means writing explicit +``verbose_name`` and ``verbose_name_plural`` options in the ``Meta`` class, +though, rather than relying on Django's default determination of +``verbose_name`` and ``verbose_name_plural`` by looking at the model's class +name:: + + from django.utils.translation import ugettext_lazy as _ + + class MyThing(models.Model): + name = models.CharField(_('name'), help_text=_('This is the help text')) + class Meta: + verbose_name = _('my thing') + verbose_name_plural = _('mythings') + +Working with lazy translation objects +------------------------------------- + +.. highlightlang:: python + +Using ``ugettext_lazy()`` and ``ungettext_lazy()`` to mark strings in models +and utility functions is a common operation. When you're working with these +objects elsewhere in your code, you should ensure that you don't accidentally +convert them to strings, because they should be converted as late as possible +(so that the correct locale is in effect). This necessitates the use of a +couple of helper functions. + +Joining strings: string_concat() +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Standard Python string joins (``''.join([...])``) will not work on lists +containing lazy translation objects. Instead, you can use +``django.utils.translation.string_concat()``, which creates a lazy object that +concatenates its contents *and* converts them to strings only when the 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') + result = string_concat(name, ': ', instrument) + +In this case, the lazy translations in ``result`` will only be converted to +strings when ``result`` itself is used in a string (usually at template +rendering time). + +The allow_lazy() decorator +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Django offers many utility functions (particularly in ``django.utils``) that +take a string as their first argument and do something to that string. These +functions are used by template filters as well as directly in other code. + +If you write your own similar functions and deal with translations, you'll +face the problem of what to do when the first argument is a lazy translation +object. You don't want to convert it to a string immediately, because you might +be using this function outside of a view (and hence the current thread's locale +setting will not be correct). + +For cases like this, use the ``django.utils.functional.allow_lazy()`` +decorator. It modifies the function so that *if* it's called with a lazy +translation as the first argument, the function evaluation is delayed until it +needs to be converted to a string. + +For example:: + + from django.utils.functional import allow_lazy + + def fancy_utility_function(s, ...): + # Do some conversion on string 's' + ... + fancy_utility_function = allow_lazy(fancy_utility_function, unicode) + +The ``allow_lazy()`` decorator takes, in addition to the function to decorate, +a number of extra arguments (``*args``) specifying the type(s) that the +original function can return. Usually, it's enough to include ``unicode`` here +and ensure that your function returns only Unicode strings. + +Using this decorator means you can write your function and assume that the +input is a proper string, then add support for lazy translation objects at the +end. + +.. _specifying-translation-strings-in-template-code: + +Specifying translation strings: In template code +================================================ + +.. highlightlang:: html+django + +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. + +``trans`` template tag +---------------------- + +The ``{% trans %}`` template tag translates either a constant string +(enclosed in single or double quotes) or variable content:: + + <title>{% trans "This is the title." %}</title> + <title>{% trans myvar %}</title> + +If the ``noop`` option is present, variable lookup still takes place but the +translation is skipped. This is useful when "stubbing out" content that will +require translation in the future:: + + <title>{% trans "myvar" noop %}</title> + +Internally, inline translations use an ``ugettext`` call. + +In case a template var (``myvar`` above) is passed to the tag, the tag will +first resolve such variable to a string at run-time and then look up that +string in the message catalogs. + +It's not possible to mix a template variable inside a string within ``{% trans +%}``. If your translations require strings with variables (placeholders), use +``{% blocktrans %}`` instead. + +``blocktrans`` template tag +--------------------------- + +Contrarily to the ``trans`` tag, the ``blocktrans`` tag allows you to mark +complex sentences consisting of literals and variable content for translation +by making use of placeholders:: + + {% blocktrans %}This string will have {{ value }} inside.{% endblocktrans %} + +To translate a template expression -- say, accessing object attributes or +using template filters -- you need to bind the expression to a local variable +for use within the translation block. Examples:: + + {% blocktrans with article.price as amount %} + That will cost $ {{ amount }}. + {% endblocktrans %} + + {% blocktrans with value|filter as myvar %} + This will have {{ myvar }} inside. + {% endblocktrans %} + +If you need to bind more than one expression inside a ``blocktrans`` tag, +separate the pieces with ``and``:: + + {% blocktrans with book|title as book_t and author|title as author_t %} + This is {{ book_t }} by {{ author_t }} + {% endblocktrans %} + +This tag also provides for pluralization. To use it: + + * Designate and bind a counter value with the name ``count``. This value will + be the one used to select the right plural form. + + * Specify both the singular and plural forms separating them with the + ``{% plural %}`` tag within the ``{% blocktrans %}`` and + ``{% endblocktrans %}`` tags. + +An example:: + + {% blocktrans count list|length as counter %} + There is only one {{ name }} object. + {% plural %} + There are {{ counter }} {{ name }} objects. + {% endblocktrans %} + +A more complex example:: + + {% blocktrans with article.price as amount count i.length as years %} + That will cost $ {{ amount }} per year. + {% plural %} + That will cost $ {{ amount }} per {{ years }} years. + {% endblocktrans %} + +When you use both the pluralization feature and bind values to local variables +in addition to the counter value, keep in mind that the ``blocktrans`` +construct is internally converted to an ``ungettext`` call. This means the +same :ref:`notes regarding ungettext variables <pluralization-var-notes>` +apply. + +.. _template-translation-vars: + +Other tags +---------- + +Each ``RequestContext`` has access to three translation-specific variables: + + * ``LANGUAGES`` is a list of tuples in which the first element is the + :term:`language code` and the second is the language name (translated into + the currently active locale). + + * ``LANGUAGE_CODE`` is the current user's preferred language, as a string. + Example: ``en-us``. (See :ref:`how-django-discovers-language-preference`.) + + * ``LANGUAGE_BIDI`` is the current locale's direction. If True, it's a + right-to-left language, e.g.: Hebrew, Arabic. If False it's a + left-to-right language, e.g.: English, French, German etc. + +If you don't use the ``RequestContext`` extension, you can get those values with +three tags:: + + {% get_current_language as LANGUAGE_CODE %} + {% get_available_languages as LANGUAGES %} + {% get_current_language_bidi as LANGUAGE_BIDI %} + +These tags also require a ``{% load i18n %}``. + +Translation hooks are also available within any template block tag that accepts +constant strings. In those cases, just use ``_()`` syntax to specify a +translation string:: + + {% some_special_tag _("Page not found") value|yesno:_("yes,no") %} + +In this case, both the tag and the filter will see the already-translated +string, so they don't need to be aware of translations. + +.. note:: + In this example, the translation infrastructure will be passed the string + ``"yes,no"``, not the individual strings ``"yes"`` and ``"no"``. The + translated string will need to contain the comma so that the filter + parsing code knows how to split up the arguments. For example, a German + translator might translate the string ``"yes,no"`` as ``"ja,nein"`` + (keeping the comma intact). + +.. _Django templates: ../templates_python/ + +Specifying translation strings: In JavaScript code +================================================== + +Adding translations to JavaScript poses some problems: + + * JavaScript code doesn't have access to a ``gettext`` implementation. + + * JavaScript code doesn't have access to .po or .mo files; they need to be + delivered by the server. + + * The translation catalogs for JavaScript should be kept as small as + possible. + +Django provides an integrated solution for these problems: It passes the +translations into JavaScript, so you can call ``gettext``, etc., from within +JavaScript. + +The ``javascript_catalog`` view +------------------------------- + +.. module:: django.views.i18n + +.. function:: javascript_catalog(request, domain='djangojs', packages=None) + +The main solution to these problems is the :meth:`django.views.i18n.javascript_catalog` +view, which sends out a JavaScript code library with functions that mimic the +``gettext`` interface, plus an array of translation strings. Those translation +strings are taken from the application, project or Django core, according to what +you specify in either the info_dict or the URL. + +You hook it up like this:: + + js_info_dict = { + 'packages': ('your.app.package',), + } + + urlpatterns = patterns('', + (r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict), + ) + +Each string in ``packages`` should be in Python dotted-package syntax (the +same format as the strings in ``INSTALLED_APPS``) and should refer to a package +that contains a ``locale`` directory. If you specify multiple packages, all +those catalogs are merged into one catalog. This is useful if you have +JavaScript that uses strings from different applications. + +By default, the view uses the ``djangojs`` gettext domain. This can be +changed by altering the ``domain`` argument. + +You can make the view dynamic by putting the packages into the URL pattern:: + + urlpatterns = patterns('', + (r'^jsi18n/(?P<packages>\S+?)/$', 'django.views.i18n.javascript_catalog'), + ) + +With this, you specify the packages as a list of package names delimited by '+' +signs in the URL. This is especially useful if your pages use code from +different apps and this changes often and you don't want to pull in one big +catalog file. As a security measure, these values can only be either +``django.conf`` or any package from the ``INSTALLED_APPS`` setting. + +Using the JavaScript translation catalog +---------------------------------------- + +To use the catalog, just pull in the dynamically generated script like this:: + + <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 +``gettext`` interface to access it:: + + document.write(gettext('this is to be translated')); + +There is also an ``ngettext`` interface:: + + var object_cnt = 1 // or 0, or 2, or 3, ... + s = ngettext('literal for the singular case', + 'literal for the plural case', object_cnt); + +and even a string interpolation function:: + + function interpolate(fmt, obj, named); + +The interpolation syntax is borrowed from Python, so the ``interpolate`` +function supports both positional and named interpolation: + + * Positional interpolation: ``obj`` contains a JavaScript Array object + whose elements values are then sequentially interpolated in their + corresponding ``fmt`` placeholders in the same order they appear. + For example:: + + fmts = ngettext('There is %s object. Remaining: %s', + 'There are %s objects. Remaining: %s', 11); + s = interpolate(fmts, [11, 20]); + // s is 'There are 11 objects. Remaining: 20' + + * Named interpolation: This mode is selected by passing the optional + boolean ``named`` parameter as true. ``obj`` contains a JavaScript + object or associative array. For example:: + + d = { + count: 10, + total: 50 + }; + + fmts = ngettext('Total: %(total)s, there is %(count)s object', + 'there are %(count)s of a total of %(total)s objects', d.count); + s = interpolate(fmts, d, true); + +You shouldn't go over the top with string interpolation, though: this is still +JavaScript, so the code has to make repeated regular-expression substitutions. +This isn't as fast as string interpolation in Python, so keep it to those +cases where you really need it (for example, in conjunction with ``ngettext`` +to produce proper pluralizations). + +The ``set_language`` redirect view +================================== + +.. function:: set_language(request) + +As a convenience, Django comes with a view, :meth:`django.views.i18n.set_language`, +that sets a user's language preference and redirects back to the previous page. + +Activate this view by adding the following line to your URLconf:: + + (r'^i18n/', include('django.conf.urls.i18n')), + +(Note that this example makes the view available at ``/i18n/setlang/``.) + +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 +language choice in a cookie that is by default named ``django_language``. +(The name can be changed through the ``LANGUAGE_COOKIE_NAME`` setting.) + +After setting the language choice, Django redirects the user, following this +algorithm: + + * Django looks for a ``next`` parameter in the ``POST`` data. + * If that doesn't exist, or is empty, Django tries the URL in the + ``Referrer`` header. + * If that's empty -- say, if a user's browser suppresses that header -- + then the user will be redirected to ``/`` (the site root) as a fallback. + +Here's example HTML template code: + +.. code-block:: html+django + + <form action="/i18n/setlang/" method="post"> + {% csrf_token %} + <input name="next" type="hidden" value="/next/page/" /> + <select name="language"> + {% for lang in LANGUAGES %} + <option value="{{ lang.0 }}">{{ lang.1 }}</option> + {% endfor %} + </select> + <input type="submit" value="Go" /> + </form> diff --git a/parts/django/docs/topics/i18n/localization.txt b/parts/django/docs/topics/i18n/localization.txt new file mode 100644 index 0000000..38d74e6 --- /dev/null +++ b/parts/django/docs/topics/i18n/localization.txt @@ -0,0 +1,317 @@ +============ +Localization +============ + +This document covers two localization-related topics: `Creating language +files`_ and `locale aware date, time and numbers input/output in forms`_ + +.. _`Creating language files`: how-to-create-language-files_ +.. _`locale aware date, time and numbers input/output in forms`: format-localization_ + +.. seealso:: + + The :doc:`/howto/i18n` document included with the Django HOW-TO documents collection. + +.. _how-to-create-language-files: + +How to create language files +============================ + +Once the string literals of an application have been tagged for later +translation, the translation themselves need to be written (or obtained). Here's +how that works. + +.. _locale-restrictions: + +.. admonition:: Locale restrictions + + Django does not support localizing your application into a locale for which + Django itself has not been translated. In this case, it will ignore your + translation files. If you were to try this and Django supported it, you + would inevitably see a mixture of translated strings (from your application) + and English strings (from Django itself). If you want to support a locale + for your application that is not already part of Django, you'll need to make + at least a minimal translation of the Django core. + + A good starting point is to copy the Django English ``.po`` file and to + translate at least some :term:`translation strings <translation string>`. + +Message files +------------- + +The first step is to create a :term:`message file` for a new language. A message +file is a plain-text file, representing a single language, that contains all +available translation strings and how they should be represented in the given +language. Message files have a ``.po`` file extension. + +Django comes with a tool, ``django-admin.py makemessages``, that automates the +creation and upkeep of these files. + +.. admonition:: A note to Django veterans + + The old tool ``bin/make-messages.py`` has been moved to the command + ``django-admin.py makemessages`` to provide consistency throughout Django. + +.. admonition:: Gettext utilities + + The ``makemessages`` command (and ``compilemessages`` discussed later) use + 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:: + + django-admin.py makemessages -l de + +...where ``de`` is the language code for the message file you want to create. +The language code, in this case, is in :term:`locale format<locale name>`. For +example, it's ``pt_BR`` for Brazilian Portuguese and ``de_AT`` for Austrian +German. + +The script should be run from one of two places: + + * The root directory of your Django project. + * The root directory of your Django app. + +The script runs over your project source tree or your application source tree +and pulls out all strings marked for translation. It creates (or updates) a +message file in the directory ``locale/LANG/LC_MESSAGES``. In the ``de`` +example, the file will be ``locale/de/LC_MESSAGES/django.po``. + +By default ``django-admin.py makemessages`` examines every file that has the +``.html`` file extension. In case you want to override that default, use the +``--extension`` or ``-e`` option to specify the file extensions to examine:: + + django-admin.py makemessages -l de -e txt + +Separate multiple extensions with commas and/or use ``-e`` or ``--extension`` +multiple times:: + + django-admin.py makemessages -l de -e html,txt -e xml + +When :ref:`creating message files from JavaScript source code +<creating-message-files-from-js-code>` you need to use the special 'djangojs' +domain, **not** ``-e js``. + +.. admonition:: No gettext? + + If you don't have the ``gettext`` utilities installed, ``django-admin.py + makemessages`` will create empty files. If that's the case, either install + the ``gettext`` utilities or just copy the English message file + (``locale/en/LC_MESSAGES/django.po``) if available and use it as a starting + point; it's just an empty translation file. + +.. admonition:: Working on Windows? + + If you're using Windows and need to install the GNU gettext utilities so + ``django-admin makemessages`` works see :ref:`gettext_on_windows` for more + information. + +The format of ``.po`` files is straightforward. Each ``.po`` file contains a +small bit of metadata, such as the translation maintainer's contact +information, but the bulk of the file is a list of **messages** -- simple +mappings between translation strings and the actual translated text for the +particular language. + +For example, if your Django app contained a translation string for the text +``"Welcome to my site."``, like so:: + + _("Welcome to my site.") + +...then ``django-admin.py makemessages`` will have created a ``.po`` file +containing the following snippet -- a message:: + + #: path/to/python/module.py:23 + msgid "Welcome to my site." + msgstr "" + +A quick explanation: + + * ``msgid`` is the translation string, which appears in the source. Don't + change it. + * ``msgstr`` is where you put the language-specific translation. It starts + out empty, so it's your responsibility to change it. Make sure you keep + the quotes around your translation. + * As a convenience, each message includes, in the form of a comment line + prefixed with ``#`` and located above the ``msgid`` line, the filename and + line number from which the translation string was gleaned. + +Long messages are a special case. There, the first string directly after the +``msgstr`` (or ``msgid``) is an empty string. Then the content itself will be +written over the next few lines as one string per line. Those strings are +directly concatenated. Don't forget trailing spaces within the strings; +otherwise, they'll be tacked together without whitespace! + +.. admonition:: Mind your charset + + When creating a PO file with your favorite text editor, first edit + the charset line (search for ``"CHARSET"``) and set it to the charset + you'll be using to edit the content. Due to the way the ``gettext`` tools + work internally and because we want to allow non-ASCII source strings in + Django's core and your applications, you **must** use UTF-8 as the encoding + for your PO file. This means that everybody will be using the same + encoding, which is important when Django processes the PO files. + +To reexamine all source code and templates for new translation strings and +update all message files for **all** languages, run this:: + + django-admin.py makemessages -a + +Compiling message files +----------------------- + +After you create your message file -- and each time you make changes to it -- +you'll need to compile it into a more efficient form, for use by ``gettext``. +Do this with the ``django-admin.py compilemessages`` utility. + +This tool runs over all available ``.po`` files and creates ``.mo`` files, which +are binary files optimized for use by ``gettext``. In the same directory from +which you ran ``django-admin.py makemessages``, run ``django-admin.py +compilemessages`` like this:: + + django-admin.py compilemessages + +That's it. Your translations are ready for use. + +.. admonition:: A note to Django veterans + + The old tool ``bin/compile-messages.py`` has been moved to the command + ``django-admin.py compilemessages`` to provide consistency throughout + Django. + +.. admonition:: Working on Windows? + + If you're using Windows and need to install the GNU gettext utilities so + ``django-admin compilemessages`` works see :ref:`gettext_on_windows` for more + information. + +.. admonition:: .po files: Encoding and BOM usage. + + Django only supports ``.po`` files encoded in UTF-8 and without any BOM + (Byte Order Mark) so if your text editor adds such marks to the beginning of + files by default then you will need to reconfigure it. + +.. _creating-message-files-from-js-code: + +Creating message files from JavaScript source code +================================================== + +You create and update the message files the same way as the other Django message +files -- with the ``django-admin.py makemessages`` tool. The only difference is +you need to provide a ``-d djangojs`` parameter, like this:: + + django-admin.py makemessages -d djangojs -l de + +This would create or update the message file for JavaScript for German. +After updating message files, just run ``django-admin.py compilemessages`` +the same way as you do with normal Django message files. + +.. _gettext_on_windows: + +``gettext`` on Windows +====================== + +This is only needed for people who either want to extract message IDs or compile +message files (``.po``). Translation work itself just involves editing existing +files of this type, but if you want to create your own message files, or want to +test or compile a changed message file, you will need the ``gettext`` utilities: + + * Download the following zip files from the GNOME servers + http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/ or from one + of its mirrors_ + + * ``gettext-runtime-X.zip`` + * ``gettext-tools-X.zip`` + + ``X`` is the version number, we are requiring ``0.15`` or higher. + + * Extract the contents of the ``bin\`` directories in both files to the + same folder on your system (i.e. ``C:\Program Files\gettext-utils``) + + * Update the system PATH: + + * ``Control Panel > System > Advanced > Environment Variables``. + * In the ``System variables`` list, click ``Path``, click ``Edit``. + * Add ``;C:\Program Files\gettext-utils\bin`` at the end of the + ``Variable value`` field. + +.. _mirrors: http://ftp.gnome.org/pub/GNOME/MIRRORS + +You may also use ``gettext`` binaries you have obtained elsewhere, so long as +the ``xgettext --version`` command works properly. Do not attempt to use Django +translation utilities with a ``gettext`` package if the command ``xgettext +--version`` entered at a Windows command prompt causes a popup window saying +"xgettext.exe has generated errors and will be closed by Windows". + +.. _format-localization: + +Format localization +=================== + +.. versionadded:: 1.2 + +Django's formatting system is disabled by default. To enable it, it's +necessary to set :setting:`USE_L10N = True <USE_L10N>` in your settings file. + +.. note:: + The default :file:`settings.py` file created by + :djadmin:`django-admin.py startproject <startproject>` includes + :setting:`USE_L10N = True <USE_L10N>` for convenience. + +When using Django's formatting system, dates and numbers on templates will be +displayed using the format specified for the current locale. Two users +accessing the same content, but in different language, will see date and +number fields formatted in different ways, depending on the format for their +current locale. + +Django will also use localized formats when parsing data in forms. That means +Django uses different formats for different locales when guessing the format +used by the user when inputting data on forms. + +.. note:: + Django uses different formats for displaying data to those it uses for + parsing data. Most notably, the formats for parsing dates can't use the + ``%a`` (abbreviated weekday name), ``%A`` (full weekday name), + ``%b`` (abbreviated month name), ``%B`` (full month name), + or ``%p`` (AM/PM). + +To enable a form field to localize input and output data simply use its +``localize`` argument:: + + class CashRegisterForm(forms.Form): + product = forms.CharField() + revenue = forms.DecimalField(max_digits=4, decimal_places=2, localize=True) + +Creating custom format files +---------------------------- + +Django provides format definitions for many locales, but sometimes you might +want to create your own, because a format files doesn't exist for your locale, +or because you want to overwrite some of the values. + +To use custom formats, first thing to do, is to specify the path where you'll +place format files. To do that, just set your :setting:`FORMAT_MODULE_PATH` +setting to the path (in the format ``'foo.bar.baz``) where format files +will exists. + +Files are not placed directly in this directory, but in a directory named as +the locale, and must be named ``formats.py``. + +To customize the English formats, a structure like this would be needed:: + + mysite/ + formats/ + __init__.py + en/ + __init__.py + formats.py + +where :file:`formats.py` contains custom format definitions. For example:: + + THOUSAND_SEPARATOR = ' ' + +to use a space as a thousand separator, instead of the default for English, +a comma. diff --git a/parts/django/docs/topics/index.txt b/parts/django/docs/topics/index.txt new file mode 100644 index 0000000..4c6b7fc --- /dev/null +++ b/parts/django/docs/topics/index.txt @@ -0,0 +1,27 @@ +Using Django +============ + +Introductions to all the key parts of Django you'll need to know: + +.. toctree:: + :maxdepth: 1 + + install + db/index + http/index + forms/index + forms/modelforms + templates + generic-views + files + testing + auth + cache + conditional-view-processing + email + i18n/index + pagination + serialization + settings + signals + diff --git a/parts/django/docs/topics/install.txt b/parts/django/docs/topics/install.txt new file mode 100644 index 0000000..20c8074 --- /dev/null +++ b/parts/django/docs/topics/install.txt @@ -0,0 +1,298 @@ +===================== +How to install Django +===================== + +This document will get you up and running with Django. + +Install Python +============== + +Being a Python Web framework, Django requires Python. + +It works with any Python version from 2.4 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). + +Get Python at http://www.python.org. If you're running Linux or Mac OS X, you +probably already have it installed. + +.. admonition:: Django on Jython + + If you use Jython_ (a Python implementation for the Java platform), you'll + need to follow a few additional steps. See :doc:`/howto/jython` for details. + +.. _jython: http://jython.org/ + +Install Apache and mod_wsgi +============================= + +If you just want to experiment with Django, skip ahead to the next section; +Django includes a lightweight Web server you can use for testing, so you won't +need to set up Apache until you're ready to deploy Django in production. + +If you want to use Django on a production site, use Apache with `mod_wsgi`_. +mod_wsgi is similar to mod_perl -- it embeds Python within Apache and loads +Python code into memory when the server starts. Code stays in memory throughout +the life of an Apache process, which leads to significant performance gains over +other server arrangements. Make sure you have Apache installed, with the +mod_wsgi module activated. Django will work with any version of Apache that +supports mod_wsgi. + +See :doc:`How to use Django with mod_wsgi </howto/deployment/modwsgi>` 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. A great second choice is :doc:`mod_python +</howto/deployment/modpython>`, the predecessor to mod_wsgi. Additionally, Django +follows the WSGI_ spec, which allows it to run on a variety of server platforms. +See the `server-arrangements wiki page`_ for specific installation instructions +for each platform. + +.. _Apache: http://httpd.apache.org/ +.. _mod_wsgi: http://code.google.com/p/modwsgi/ +.. _WSGI: http://www.python.org/dev/peps/pep-0333/ +.. _server-arrangements wiki page: http://code.djangoproject.com/wiki/ServerArrangements + +.. _database-installation: + +Get your database running +========================= + +If you plan to use Django's database API functionality, you'll need to make +sure a database server is running. Django supports many different database +servers and is officially supported with PostgreSQL_, MySQL_, Oracle_ and +SQLite_ (although SQLite doesn't require a separate server to be running). + +In addition to the officially supported databases, there are backends provided +by 3rd parties that allow you to use other databases with Django: + +* `Sybase SQL Anywhere`_ +* `IBM DB2`_ +* `Microsoft SQL Server 2005`_ +* Firebird_ +* ODBC_ + +The Django versions and ORM features supported by these unofficial backends +vary considerably. Queries regarding the specific capabilities of these +unofficial backends, along with any support queries, should be directed to the +support channels provided by each 3rd party project. + +In addition to a database backend, you'll need to make sure your Python +database bindings are installed. + +* If you're using PostgreSQL, you'll need the psycopg_ package. Django supports + both version 1 and 2. (When you configure Django's database layer, specify + either ``postgresql`` [for version 1] or ``postgresql_psycopg2`` [for version 2].) + You might want to refer to our :ref:`PostgreSQL notes <postgresql-notes>` for + further technical details specific to this database. + + 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 + will also want to read the database-specific :ref:`notes for the MySQL + backend <mysql-notes>`. + +* If you're using SQLite and Python 2.4, you'll need pysqlite_. Use version + 2.0.3 or higher. Python 2.5 ships with an SQLite wrapper in the standard + library, so you don't need to install anything extra in that case. Please + read the :ref:`SQLite backend notes <sqlite-notes>`. + +* If you're using Oracle, you'll need a copy of cx_Oracle_, but please + read the database-specific :ref:`notes for the Oracle backend <oracle-notes>` + for important information regarding supported versions of both Oracle and + ``cx_Oracle``. + +* If you're using an unofficial 3rd party backend, please consult the + documentation provided for any additional requirements. + +If you plan to use Django's ``manage.py syncdb`` command to +automatically create database tables for your models, you'll need to +ensure that Django has permission to create and alter tables in the +database you're using; if you plan to manually create the tables, you +can simply grant Django ``SELECT``, ``INSERT``, ``UPDATE`` and +``DELETE`` permissions. On some databases, Django will need +``ALTER TABLE`` privileges during ``syncdb`` but won't issue +``ALTER TABLE`` statements on a table once ``syncdb`` has created it. + +If you're using Django's :doc:`testing framework</topics/testing>` to test database queries, +Django will need permission to create a test database. + +.. _PostgreSQL: http://www.postgresql.org/ +.. _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/ +.. _Oracle: http://www.oracle.com/ +.. _Sybase SQL Anywhere: http://code.google.com/p/sqlany-django/ +.. _IBM DB2: http://code.google.com/p/ibm-db/ +.. _Microsoft SQL Server 2005: http://code.google.com/p/django-mssql/ +.. _Firebird: http://code.google.com/p/django-firebird/ +.. _ODBC: http://code.google.com/p/django-pyodbc/ +.. _removing-old-versions-of-django: + +Remove any old versions of Django +================================= + +If you are upgrading your installation of Django from a previous version, +you will need to uninstall the old Django version before installing the +new version. + +If you installed Django using ``setup.py install``, uninstalling +is as simple as deleting the ``django`` directory from your Python +``site-packages``. + +If you installed Django from a Python egg, remove the Django ``.egg`` file, +and remove the reference to the egg in the file named ``easy-install.pth``. +This file should also be located in your ``site-packages`` directory. + +.. admonition:: Where are my ``site-packages`` stored? + + The location of the ``site-packages`` directory depends on the operating + system, and the location in which Python was installed. To find out your + system's ``site-packages`` location, execute the following: + + .. code-block:: bash + + python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" + + (Note that this should be run from a shell prompt, not a Python interactive + prompt.) + +.. _install-django-code: + +Install the Django code +======================= + +Installation instructions are slightly different depending on whether you're +installing a distribution-specific package, downloading the latest official +release, or fetching the latest development version. + +It's easy, no matter which way you choose. + +Installing a distribution-specific package +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Check the :doc:`distribution specific notes </misc/distributions>` to see if your +platform/distribution provides official Django packages/installers. +Distribution-provided packages will typically allow for automatic installation +of dependencies and easy upgrade paths. + +.. _installing-official-release: + +Installing an official release +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + 1. Download the latest release from our `download page`_. + + 2. Untar the downloaded file (e.g. ``tar xzvf Django-NNN.tar.gz``, + where ``NNN`` is the version number of the latest release). + If you're using Windows, you can download the command-line tool + bsdtar_ to do this, or you can use a GUI-based tool such as 7-zip_. + + 3. Change into the directory created in step 2 (e.g. ``cd Django-NNN``). + + 4. If you're using Linux, Mac OS X or some other flavor of Unix, enter + the command ``sudo python setup.py install`` at the shell prompt. + If you're using Windows, start up a command shell with administrator + privileges and run the command ``setup.py install``. + +These commands will install Django in your Python installation's +``site-packages`` directory. + +.. _bsdtar: http://gnuwin32.sourceforge.net/packages/bsdtar.htm +.. _7-zip: http://www.7-zip.org/ + +.. _installing-development-version: + +Installing the development version +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. admonition:: Tracking Django development + + If you decide to use the latest development version of Django, + you'll want to pay close attention to `the development timeline`_, + and you'll want to keep an eye on `the list of + backwards-incompatible changes`_. This will help you stay on top + of any new features you might want to use, as well as any changes + you'll need to make to your code when updating your copy of Django. + (For stable releases, any necessary changes are documented in the + release notes.) + +.. _the development timeline: http://code.djangoproject.com/timeline +.. _the list of backwards-incompatible changes: http://code.djangoproject.com/wiki/BackwardsIncompatibleChanges + +If you'd like to be able to update your Django code occasionally with the +latest bug fixes and improvements, follow these instructions: + +1. Make sure that you have Subversion_ installed, and that you can run its + commands from a shell. (Enter ``svn help`` at a shell prompt to test + this.) + +2. Check out Django's main development branch (the 'trunk') like so: + + .. code-block:: bash + + svn co http://code.djangoproject.com/svn/django/trunk/ django-trunk + +3. Next, make sure that the Python interpreter can load Django's code. There + are various ways of accomplishing this. One of the most convenient, on + Linux, Mac OSX or other Unix-like systems, is to use a symbolic link: + + .. code-block:: bash + + ln -s WORKING-DIR/django-trunk/django SITE-PACKAGES-DIR/django + + (In the above line, change ``SITE-PACKAGES-DIR`` to match the location of + your system's ``site-packages`` directory, as explained in the + "Where are my ``site-packages`` stored?" section above. Change WORKING-DIR + to match the full path to your new ``django-trunk`` directory.) + + Alternatively, you can define your ``PYTHONPATH`` environment variable + so that it includes the ``django-trunk`` directory. This is perhaps the + most convenient solution on Windows systems, which don't support symbolic + links. (Environment variables can be defined on Windows systems `from the + Control Panel`_.) + + .. admonition:: What about Apache and mod_python? + + If you take the approach of setting ``PYTHONPATH``, you'll need to + remember to do the same thing in your Apache configuration once you + deploy your production site. Do this by setting ``PythonPath`` in your + Apache configuration file. + + More information about deployment is available, of course, in our + :doc:`How to use Django with mod_python </howto/deployment/modpython>` + documentation. + +4. On Unix-like systems, create a symbolic link to the file + ``django-trunk/django/bin/django-admin.py`` in a directory on your system + path, such as ``/usr/local/bin``. For example: + + .. code-block:: bash + + ln -s WORKING-DIR/django-trunk/django/bin/django-admin.py /usr/local/bin + + (In the above line, change WORKING-DIR to match the full path to your new + ``django-trunk`` directory.) + + This simply lets you type ``django-admin.py`` from within any directory, + rather than having to qualify the command with the full path to the file. + + On Windows systems, the same result can be achieved by copying the file + ``django-trunk/django/bin/django-admin.py`` to somewhere on your system + path, for example ``C:\Python24\Scripts``. + +You *don't* have to run ``python setup.py install``, because you've already +carried out the equivalent actions in steps 3 and 4. + +When you want to update your copy of the Django source code, just run the +command ``svn update`` from within the ``django-trunk`` directory. When you do +this, Subversion will automatically download any changes. + +.. _`download page`: http://www.djangoproject.com/download/ +.. _Subversion: http://subversion.tigris.org/ +.. _from the Control Panel: http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/sysdm_advancd_environmnt_addchange_variable.mspx diff --git a/parts/django/docs/topics/pagination.txt b/parts/django/docs/topics/pagination.txt new file mode 100644 index 0000000..ee8a433 --- /dev/null +++ b/parts/django/docs/topics/pagination.txt @@ -0,0 +1,281 @@ +========== +Pagination +========== + +.. module:: django.core.paginator + :synopsis: Classes to help you easily manage paginated data. + +.. versionchanged:: 1.0 + Pagination facilities have been almost fully reworked. + +Django provides a few classes that help you manage paginated data -- that is, +data that's split across several pages, with "Previous/Next" links. These +classes live in :file:`django/core/paginator.py`. + +Example +======= + +Give :class:`Paginator` a list of objects, plus the number of items you'd like to +have on each page, and it gives you methods for accessing the items for each +page:: + + >>> from django.core.paginator import Paginator + >>> objects = ['john', 'paul', 'george', 'ringo'] + >>> p = Paginator(objects, 2) + + >>> p.count + 4 + >>> p.num_pages + 2 + >>> p.page_range + [1, 2] + + >>> page1 = p.page(1) + >>> page1 + <Page 1 of 2> + >>> page1.object_list + ['john', 'paul'] + + >>> page2 = p.page(2) + >>> page2.object_list + ['george', 'ringo'] + >>> page2.has_next() + False + >>> page2.has_previous() + True + >>> page2.has_other_pages() + True + >>> page2.next_page_number() + 3 + >>> page2.previous_page_number() + 1 + >>> page2.start_index() # The 1-based index of the first item on this page + 3 + >>> page2.end_index() # The 1-based index of the last item on this page + 4 + + >>> p.page(0) + Traceback (most recent call last): + ... + EmptyPage: That page number is less than 1 + >>> p.page(3) + Traceback (most recent call last): + ... + EmptyPage: That page contains no results + +.. note:: + + Note that you can give ``Paginator`` a list/tuple, a Django ``QuerySet``, or + any other object with a ``count()`` or ``__len__()`` method. When + determining the number of objects contained in the passed object, + ``Paginator`` will first try calling ``count()``, then fallback to using + ``len()`` if the passed object has no ``count()`` method. This allows + objects such as Django's ``QuerySet`` to use a more efficient ``count()`` + method when available. + + +Using ``Paginator`` in a view +============================== + +Here's a slightly more complex example using :class:`Paginator` in a view to +paginate a queryset. We give both the view and the accompanying template to +show how you can display the results. This example assumes you have a +``Contacts`` model that has already been imported. + +The view function looks like this:: + + from django.core.paginator import Paginator, InvalidPage, EmptyPage + + def listing(request): + contact_list = Contacts.objects.all() + paginator = Paginator(contact_list, 25) # Show 25 contacts per page + + # Make sure page request is an int. If not, deliver first page. + try: + page = int(request.GET.get('page', '1')) + except ValueError: + page = 1 + + # If page request (9999) is out of range, deliver last page of results. + try: + contacts = paginator.page(page) + except (EmptyPage, InvalidPage): + contacts = paginator.page(paginator.num_pages) + + return render_to_response('list.html', {"contacts": contacts}) + +In the template :file:`list.html`, you'll want to include navigation between +pages along with any interesting information from the objects themselves:: + + {% for contact in contacts.object_list %} + {# Each "contact" is a Contact model object. #} + {{ contact.full_name|upper }}<br /> + ... + {% endfor %} + + <div class="pagination"> + <span class="step-links"> + {% if contacts.has_previous %} + <a href="?page={{ contacts.previous_page_number }}">previous</a> + {% endif %} + + <span class="current"> + Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}. + </span> + + {% if contacts.has_next %} + <a href="?page={{ contacts.next_page_number }}">next</a> + {% endif %} + </span> + </div> + + +``Paginator`` objects +===================== + +The :class:`Paginator` class has this constructor: + +.. class:: Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True) + +Required arguments +------------------ + +``object_list`` + A list, tuple, Django ``QuerySet``, or other sliceable object with a + ``count()`` or ``__len__()`` method. + +``per_page`` + The maximum number of items to include on a page, not including orphans + (see the ``orphans`` optional argument below). + +Optional arguments +------------------ + +``orphans`` + The minimum number of items allowed on the last page, defaults to zero. + Use this when you don't want to have a last page with very few items. + If the last page would normally have a number of items less than or equal + to ``orphans``, then those items will be added to the previous page (which + becomes the last page) instead of leaving the items on a page by + themselves. For example, with 23 items, ``per_page=10``, and + ``orphans=3``, there will be two pages; the first page with 10 items and + the second (and last) page with 13 items. + +``allow_empty_first_page`` + Whether or not the first page is allowed to be empty. If ``False`` and + ``object_list`` is empty, then an ``EmptyPage`` error will be raised. + +Methods +------- + +.. method:: Paginator.page(number) + + Returns a :class:`Page` object with the given 1-based index. Raises + :exc:`InvalidPage` if the given page number doesn't exist. + +Attributes +---------- + +.. attribute:: Paginator.count + + The total number of objects, across all pages. + + .. note:: + + When determining the number of objects contained in ``object_list``, + ``Paginator`` will first try calling ``object_list.count()``. If + ``object_list`` has no ``count()`` method, then ``Paginator`` will + fallback to using ``object_list.__len__()``. This allows objects, such + as Django's ``QuerySet``, to use a more efficient ``count()`` method + when available. + +.. attribute:: Paginator.num_pages + + The total number of pages. + +.. attribute:: Paginator.page_range + + A 1-based range of page numbers, e.g., ``[1, 2, 3, 4]``. + +``InvalidPage`` exceptions +========================== + +The ``page()`` method raises ``InvalidPage`` if the requested page is invalid +(i.e., not an integer) or contains no objects. Generally, it's enough to trap +the ``InvalidPage`` exception, but if you'd like more granularity, you can trap +either of the following exceptions: + +``PageNotAnInteger`` + Raised when ``page()`` is given a value that isn't an integer. + +``EmptyPage`` + Raised when ``page()`` is given a valid value but no objects exist on that + page. + +Both of the exceptions are subclasses of ``InvalidPage``, so you can handle +them both with a simple ``except InvalidPage``. + + +``Page`` objects +================ + +.. class:: Page(object_list, number, paginator) + +You usually won't construct :class:`Pages <Page>` by hand -- you'll get them +using :meth:`Paginator.page`. + + +Methods +------- + +.. method:: Page.has_next() + + Returns ``True`` if there's a next page. + +.. method:: Page.has_previous() + + Returns ``True`` if there's a previous page. + +.. method:: Page.has_other_pages() + + Returns ``True`` if there's a next *or* previous page. + +.. 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. + +.. 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. + +.. method:: Page.start_index() + + Returns the 1-based index of the first object on the page, relative to all + of the objects in the paginator's list. For example, when paginating a list + of 5 objects with 2 objects per page, the second page's :meth:`~Page.start_index` + would return ``3``. + +.. method:: Page.end_index() + + Returns the 1-based index of the last object on the page, relative to all of + the objects in the paginator's list. For example, when paginating a list of + 5 objects with 2 objects per page, the second page's :meth:`~Page.end_index` + would return ``4``. + +Attributes +---------- + +.. attribute:: Page.object_list + + The list of objects on this page. + +.. attribute:: Page.number + + The 1-based page number for this page. + +.. attribute:: Page.paginator + + The associated :class:`Paginator` object. + diff --git a/parts/django/docs/topics/serialization.txt b/parts/django/docs/topics/serialization.txt new file mode 100644 index 0000000..c8acc85 --- /dev/null +++ b/parts/django/docs/topics/serialization.txt @@ -0,0 +1,402 @@ +========================== +Serializing Django objects +========================== + +Django's serialization framework provides a mechanism for "translating" Django +objects into other formats. Usually these other formats will be text-based and +used for sending Django objects over a wire, but it's possible for a +serializer to handle any format (text-based or not). + +.. seealso:: + + If you just want to get some data from your tables into a serialized + form, you could use the :djadmin:`dumpdata` management command. + +Serializing data +---------------- + +At the highest level, serializing data is a very simple operation:: + + from django.core import serializers + data = serializers.serialize("xml", SomeModel.objects.all()) + +The arguments to the ``serialize`` function are the format to serialize the data +to (see `Serialization formats`_) and a :class:`~django.db.models.QuerySet` to +serialize. (Actually, the second argument can be any iterator that yields Django +objects, but it'll almost always be a QuerySet). + +You can also use a serializer object directly:: + + XMLSerializer = serializers.get_serializer("xml") + xml_serializer = XMLSerializer() + xml_serializer.serialize(queryset) + data = xml_serializer.getvalue() + +This is useful if you want to serialize data directly to a file-like object +(which includes an :class:`~django.http.HttpResponse`):: + + out = open("file.xml", "w") + xml_serializer.serialize(SomeModel.objects.all(), stream=out) + +Subset of fields +~~~~~~~~~~~~~~~~ + +If you only want a subset of fields to be serialized, you can +specify a ``fields`` argument to the serializer:: + + from django.core import serializers + data = serializers.serialize('xml', SomeModel.objects.all(), fields=('name','size')) + +In this example, only the ``name`` and ``size`` attributes of each model will +be serialized. + +.. note:: + + Depending on your model, you may find that it is not possible to + deserialize a model that only serializes a subset of its fields. If a + serialized object doesn't specify all the fields that are required by a + model, the deserializer will not be able to save deserialized instances. + +Inherited Models +~~~~~~~~~~~~~~~~ + +If you have a model that is defined using an :ref:`abstract base class +<abstract-base-classes>`, you don't have to do anything special to serialize +that model. Just call the serializer on the object (or objects) that you want to +serialize, and the output will be a complete representation of the serialized +object. + +However, if you have a model that uses :ref:`multi-table inheritance +<multi-table-inheritance>`, you also need to serialize all of the base classes +for the model. This is because only the fields that are locally defined on the +model will be serialized. For example, consider the following models:: + + class Place(models.Model): + name = models.CharField(max_length=50) + + class Restaurant(Place): + serves_hot_dogs = models.BooleanField() + +If you only serialize the Restaurant model:: + + data = serializers.serialize('xml', Restaurant.objects.all()) + +the fields on the serialized output will only contain the `serves_hot_dogs` +attribute. The `name` attribute of the base class will be ignored. + +In order to fully serialize your Restaurant instances, you will need to +serialize the Place models as well:: + + all_objects = list(Restaurant.objects.all()) + list(Place.objects.all()) + data = serializers.serialize('xml', all_objects) + +Deserializing data +------------------ + +Deserializing data is also a fairly simple operation:: + + for obj in serializers.deserialize("xml", data): + do_something_with(obj) + +As you can see, the ``deserialize`` function takes the same format argument as +``serialize``, a string or stream of data, and returns an iterator. + +However, here it gets slightly complicated. The objects returned by the +``deserialize`` iterator *aren't* simple Django objects. Instead, they are +special ``DeserializedObject`` instances that wrap a created -- but unsaved -- +object and any associated relationship data. + +Calling ``DeserializedObject.save()`` saves the object to the database. + +This ensures that deserializing is a non-destructive operation even if the +data in your serialized representation doesn't match what's currently in the +database. Usually, working with these ``DeserializedObject`` instances looks +something like:: + + for deserialized_object in serializers.deserialize("xml", data): + if object_should_be_saved(deserialized_object): + deserialized_object.save() + +In other words, the usual use is to examine the deserialized objects to make +sure that they are "appropriate" for saving before doing so. Of course, if you +trust your data source you could just save the object and move on. + +The Django object itself can be inspected as ``deserialized_object.object``. + +.. _serialization-formats: + +Serialization formats +--------------------- + +Django supports a number of serialization formats, some of which require you +to install third-party Python modules: + + ========== ============================================================== + Identifier Information + ========== ============================================================== + ``xml`` Serializes to and from a simple XML dialect. + + ``json`` Serializes to and from JSON_ (using a version of simplejson_ + bundled with Django). + + ``yaml`` Serializes to YAML (YAML Ain't a Markup Language). This + serializer is only available if PyYAML_ is installed. + ========== ============================================================== + +.. _json: http://json.org/ +.. _simplejson: http://undefined.org/python/#simplejson +.. _PyYAML: http://www.pyyaml.org/ + +Notes for specific serialization formats +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +json +^^^^ + +If you're using UTF-8 (or any other non-ASCII encoding) data with the JSON +serializer, you must pass ``ensure_ascii=False`` as a parameter to the +``serialize()`` call. Otherwise, the output won't be encoded correctly. + +For example:: + + json_serializer = serializers.get_serializer("json")() + json_serializer.serialize(queryset, ensure_ascii=False, stream=response) + +The Django source code includes the simplejson_ module. However, if you're +using Python 2.6 or later (which includes a builtin version of the module), Django will +use the builtin ``json`` module automatically. If you have a system installed +version that includes the C-based speedup extension, or your system version is +more recent than the version shipped with Django (currently, 2.0.7), the +system version will be used instead of the version included with Django. + +Be aware that if you're serializing using that module directly, not all Django +output can be passed unmodified to simplejson. In particular, :ref:`lazy +translation objects <lazy-translations>` need a `special encoder`_ written for +them. Something like this will work:: + + from django.utils.functional import Promise + from django.utils.encoding import force_unicode + + class LazyEncoder(simplejson.JSONEncoder): + def default(self, obj): + if isinstance(obj, Promise): + return force_unicode(obj) + return super(LazyEncoder, self).default(obj) + +.. _special encoder: http://svn.red-bean.com/bob/simplejson/tags/simplejson-1.7/docs/index.html + +.. _topics-serialization-natural-keys: + +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 types of +object, but it can cause difficulty in some circumstances. + +Consider the case of a list of objects that have foreign key on +:class:`ContentType`. If you're going to serialize an object that +refers to a content type, you need to have a way to refer to that +content type. Content Types are automatically created by Django as +part of the database synchronization process, so you don't need to +include content types in a fixture or other serialized data. As a +result, the primary key of any given content type isn't easy to +predict - it will depend on how and when :djadmin:`syncdb` was +executed to create the content types. + +There is also the matter of convenience. An integer id isn't always +the most convenient way to refer to an object; sometimes, a +more natural reference would be helpful. + +It is for these reasons that Django provides *natural keys*. A natural +key is a tuple of values that can be used to uniquely identify an +object instance without using the primary key value. + +Deserialization of natural keys +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Consider the following two models:: + + from django.db import models + + class Person(models.Model): + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + + birthdate = models.DateField() + + class Meta: + unique_together = (('first_name', 'last_name'),) + + class Book(models.Model): + name = models.CharField(max_length=100) + author = models.ForeignKey(Person) + +Ordinarily, serialized data for ``Book`` would use an integer to refer to +the author. For example, in JSON, a Book might be serialized as:: + + ... + { + "pk": 1, + "model": "store.book", + "fields": { + "name": "Mostly Harmless", + "author": 42 + } + } + ... + +This isn't a particularly natural way to refer to an author. It +requires that you know the primary key value for the author; it also +requires that this primary key value is stable and predictable. + +However, if we add natural key handling to Person, the fixture becomes +much more humane. To add natural key handling, you define a default +Manager for Person with a ``get_by_natural_key()`` method. In the case +of a Person, a good natural key might be the pair of first and last +name:: + + from django.db import models + + class PersonManager(models.Manager): + def get_by_natural_key(self, first_name, last_name): + return self.get(first_name=first_name, last_name=last_name) + + class Person(models.Model): + objects = PersonManager() + + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + + birthdate = models.DateField() + + class Meta: + unique_together = (('first_name', 'last_name'),) + +Now books can use that natural key to refer to ``Person`` objects:: + + ... + { + "pk": 1, + "model": "store.book", + "fields": { + "name": "Mostly Harmless", + "author": ["Douglas", "Adams"] + } + } + ... + +When you try to load this serialized data, Django will use the +``get_by_natural_key()`` method to resolve ``["Douglas", "Adams"]`` +into the primary key of an actual ``Person`` object. + +.. note:: + + Whatever fields you use for a natural key must be able to uniquely + identify an object. This will usually mean that your model will + have a uniqueness clause (either unique=True on a single field, or + ``unique_together`` over multiple fields) for the field or fields + in your natural key. However, uniqueness doesn't need to be + enforced at the database level. If you are certain that a set of + fields will be effectively unique, you can still use those fields + as a natural key. + +Serialization of natural keys +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +So how do you get Django to emit a natural key when serializing an object? +Firstly, you need to add another method -- this time to the model itself:: + + class Person(models.Model): + objects = PersonManager() + + first_name = models.CharField(max_length=100) + last_name = models.CharField(max_length=100) + + birthdate = models.DateField() + + def natural_key(self): + return (self.first_name, self.last_name) + + class Meta: + unique_together = (('first_name', 'last_name'),) + +That method should always return a natural key tuple -- in this +example, ``(first name, last name)``. Then, when you call +``serializers.serialize()``, you provide a ``use_natural_keys=True`` +argument:: + + >>> serializers.serialize('json', [book1, book2], indent=2, use_natural_keys=True) + +When ``use_natural_keys=True`` is specified, Django will use the +``natural_key()`` method to serialize any reference to objects of the +type that defines the method. + +If you are using :djadmin:`dumpdata` to generate serialized data, you +use the `--natural` command line flag to generate natural keys. + +.. note:: + + You don't need to define both ``natural_key()`` and + ``get_by_natural_key()``. If you don't want Django to output + natural keys during serialization, but you want to retain the + ability to load natural keys, then you can opt to not implement + the ``natural_key()`` method. + + Conversely, if (for some strange reason) you want Django to output + natural keys during serialization, but *not* be able to load those + key values, just don't define the ``get_by_natural_key()`` method. + +Dependencies during serialization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since natural keys rely on database lookups to resolve references, it +is important that data exists before it is referenced. You can't make +a `forward reference` with natural keys - the data you are referencing +must exist before you include a natural key reference to that data. + +To accommodate this limitation, calls to :djadmin:`dumpdata` that use +the :djadminopt:`--natural` option will serialize any model with a +``natural_key()`` method before it serializes normal key objects. + +However, this may not always be enough. If your natural key refers to +another object (by using a foreign key or natural key to another object +as part of a natural key), then you need to be able to ensure that +the objects on which a natural key depends occur in the serialized data +before the natural key requires them. + +To control this ordering, you can define dependencies on your +``natural_key()`` methods. You do this by setting a ``dependencies`` +attribute on the ``natural_key()`` method itself. + +For example, consider the ``Permission`` model in ``contrib.auth``. +The following is a simplified version of the ``Permission`` model:: + + class Permission(models.Model): + name = models.CharField(max_length=50) + content_type = models.ForeignKey(ContentType) + codename = models.CharField(max_length=100) + # ... + def natural_key(self): + return (self.codename,) + self.content_type.natural_key() + +The natural key for a ``Permission`` is a combination of the codename for the +``Permission``, and the ``ContentType`` to which the ``Permission`` applies. This means +that ``ContentType`` must be serialized before ``Permission``. To define this +dependency, we add one extra line:: + + class Permission(models.Model): + # ... + def natural_key(self): + return (self.codename,) + self.content_type.natural_key() + natural_key.dependencies = ['contenttypes.contenttype'] + +This definition ensures that ``ContentType`` models are serialized before +``Permission`` models. In turn, any object referencing ``Permission`` will +be serialized after both ``ContentType`` and ``Permission``. diff --git a/parts/django/docs/topics/settings.txt b/parts/django/docs/topics/settings.txt new file mode 100644 index 0000000..59c02c3 --- /dev/null +++ b/parts/django/docs/topics/settings.txt @@ -0,0 +1,255 @@ +=============== +Django settings +=============== + +A Django settings file contains all the configuration of your Django +installation. This document explains how settings work and which settings are +available. + +The basics +========== + +A settings file is just a Python module with module-level variables. + +Here are a couple of example settings:: + + DEBUG = False + DEFAULT_FROM_EMAIL = 'webmaster@example.com' + TEMPLATE_DIRS = ('/home/templates/mike', '/home/templates/john') + +Because a settings file is a Python module, the following apply: + + * It doesn't allow for Python syntax errors. + * It can assign settings dynamically using normal Python syntax. + For example:: + + MY_SETTING = [str(i) for i in range(30)] + + * It can import values from other settings files. + +.. _django-settings-module: + +Designating the settings +======================== + +When you use Django, you have to tell it which settings you're using. Do this +by using an environment variable, ``DJANGO_SETTINGS_MODULE``. + +The value of ``DJANGO_SETTINGS_MODULE`` should be in Python path syntax, e.g. +``mysite.settings``. Note that the settings module should be on the +Python `import search path`_. + +.. _import search path: http://diveintopython.org/getting_to_know_python/everything_is_an_object.html + +The django-admin.py utility +--------------------------- + +When using :doc:`django-admin.py </ref/django-admin>`, you can either set the +environment variable once, or explicitly pass in the settings module each time +you run the utility. + +Example (Unix Bash shell):: + + export DJANGO_SETTINGS_MODULE=mysite.settings + django-admin.py runserver + +Example (Windows shell):: + + set DJANGO_SETTINGS_MODULE=mysite.settings + django-admin.py runserver + +Use the ``--settings`` command-line argument to specify the settings manually:: + + django-admin.py runserver --settings=mysite.settings + +.. _django-admin.py: ../django-admin/ + +On the server (mod_python) +-------------------------- + +In your live server environment, you'll need to tell Apache/mod_python which +settings file to use. Do that with ``SetEnv``:: + + <Location "/mysite/"> + SetHandler python-program + PythonHandler django.core.handlers.modpython + SetEnv DJANGO_SETTINGS_MODULE mysite.settings + </Location> + +Read the :doc:`Django mod_python documentation </howto/deployment/modpython>` for +more information. + +Default settings +================ + +A Django settings file doesn't have to define any settings if it doesn't need +to. Each setting has a sensible default value. These defaults live in the +module :file:`django/conf/global_settings.py`. + +Here's the algorithm Django uses in compiling settings: + + * Load settings from ``global_settings.py``. + * Load settings from the specified settings file, overriding the global + settings as necessary. + +Note that a settings file should *not* import from ``global_settings``, because +that's redundant. + +Seeing which settings you've changed +------------------------------------ + +There's an easy way to view which of your settings deviate from the default +settings. The command ``python manage.py diffsettings`` displays differences +between the current settings file and Django's default settings. + +For more, see the :djadmin:`diffsettings` documentation. + +Using settings in Python code +============================= + +In your Django apps, use settings by importing the object +``django.conf.settings``. Example:: + + from django.conf import settings + + if settings.DEBUG: + # Do something + +Note that ``django.conf.settings`` isn't a module -- it's an object. So +importing individual settings is not possible:: + + from django.conf.settings import DEBUG # This won't work. + +Also note that your code should *not* import from either ``global_settings`` or +your own settings file. ``django.conf.settings`` abstracts the concepts of +default settings and site-specific settings; it presents a single interface. +It also decouples the code that uses settings from the location of your +settings. + +Altering settings at runtime +============================ + +You shouldn't alter settings in your applications at runtime. For example, +don't do this in a view:: + + from django.conf import settings + + settings.DEBUG = True # Don't do this! + +The only place you should assign to settings is in a settings file. + +Security +======== + +Because a settings file contains sensitive information, such as the database +password, you should make every attempt to limit access to it. For example, +change its file permissions so that only you and your Web server's user can +read it. This is especially important in a shared-hosting environment. + +Available settings +================== + +For a full list of available settings, see the :doc:`settings reference </ref/settings>`. + +Creating your own settings +========================== + +There's nothing stopping you from creating your own settings, for your own +Django apps. Just follow these conventions: + + * Setting names are in all uppercase. + * Don't reinvent an already-existing setting. + +For settings that are sequences, Django itself uses tuples, rather than lists, +but this is only a convention. + +.. _settings-without-django-settings-module: + +Using settings without setting DJANGO_SETTINGS_MODULE +===================================================== + +In some cases, you might want to bypass the ``DJANGO_SETTINGS_MODULE`` +environment variable. For example, if you're using the template system by +itself, you likely don't want to have to set up an environment variable +pointing to a settings module. + +In these cases, you can configure Django's settings manually. Do this by +calling: + +.. function:: django.conf.settings.configure(default_settings, **settings) + +Example:: + + from django.conf import settings + + settings.configure(DEBUG=True, TEMPLATE_DEBUG=True, + TEMPLATE_DIRS=('/home/web-apps/myapp', '/home/web-apps/base')) + +Pass ``configure()`` as many keyword arguments as you'd like, with each keyword +argument representing a setting and its value. Each argument name should be all +uppercase, with the same name as the settings described above. If a particular +setting is not passed to ``configure()`` and is needed at some later point, +Django will use the default setting value. + +Configuring Django in this fashion is mostly necessary -- and, indeed, +recommended -- when you're using a piece of the framework inside a larger +application. + +Consequently, when configured via ``settings.configure()``, Django will not +make any modifications to the process environment variables (see the +documentation of :setting:`TIME_ZONE` for why this would normally occur). It's +assumed that you're already in full control of your environment in these +cases. + +Custom default settings +----------------------- + +If you'd like default values to come from somewhere other than +``django.conf.global_settings``, you can pass in a module or class that +provides the default settings as the ``default_settings`` argument (or as the +first positional argument) in the call to ``configure()``. + +In this example, default settings are taken from ``myapp_defaults``, and the +``DEBUG`` setting is set to ``True``, regardless of its value in +``myapp_defaults``:: + + from django.conf import settings + from myapp import myapp_defaults + + settings.configure(default_settings=myapp_defaults, DEBUG=True) + +The following example, which uses ``myapp_defaults`` as a positional argument, +is equivalent:: + + settings.configure(myapp_defaults, DEBUG = True) + +Normally, you will not need to override the defaults in this fashion. The +Django defaults are sufficiently tame that you can safely use them. Be aware +that if you do pass in a new default module, it entirely *replaces* the Django +defaults, so you must specify a value for every possible setting that might be +used in that code you are importing. Check in +``django.conf.settings.global_settings`` for the full list. + +Either configure() or DJANGO_SETTINGS_MODULE is required +-------------------------------------------------------- + +If you're not setting the ``DJANGO_SETTINGS_MODULE`` environment variable, you +*must* call ``configure()`` at some point before using any code that reads +settings. + +If you don't set ``DJANGO_SETTINGS_MODULE`` and don't call ``configure()``, +Django will raise an ``ImportError`` exception the first time a setting +is accessed. + +If you set ``DJANGO_SETTINGS_MODULE``, access settings values somehow, *then* +call ``configure()``, Django will raise a ``RuntimeError`` indicating +that settings have already been configured. + +Also, it's an error to call ``configure()`` more than once, or to call +``configure()`` after any setting has been accessed. + +It boils down to this: Use exactly one of either ``configure()`` or +``DJANGO_SETTINGS_MODULE``. Not both, and not neither. + +.. _@login_required: ../authentication/#the-login-required-decorator + diff --git a/parts/django/docs/topics/signals.txt b/parts/django/docs/topics/signals.txt new file mode 100644 index 0000000..35e111d --- /dev/null +++ b/parts/django/docs/topics/signals.txt @@ -0,0 +1,255 @@ +======= +Signals +======= + +.. module:: django.dispatch + :synopsis: Signal dispatch + +Django includes a "signal dispatcher" which helps allow decoupled applications +get notified when actions occur elsewhere in the framework. In a nutshell, +signals allow certain *senders* to notify a set of *receivers* that some action +has taken place. They're especially useful when many pieces of code may be +interested in the same events. + +Django provides a :doc:`set of built-in signals </ref/signals>` that let user +code get notified by Django itself of certain actions. These include some useful +notifications: + + * :data:`django.db.models.signals.pre_save` & + :data:`django.db.models.signals.post_save` + + Sent before or after a model's :meth:`~django.db.models.Model.save` method + is called. + + * :data:`django.db.models.signals.pre_delete` & + :data:`django.db.models.signals.post_delete` + + Sent before or after a model's :meth:`~django.db.models.Model.delete` + method is called. + + * :data:`django.db.models.signals.m2m_changed` + + Sent when a :class:`ManyToManyField` on a model is changed. + + * :data:`django.core.signals.request_started` & + :data:`django.core.signals.request_finished` + + Sent when Django starts or finishes an HTTP request. + +See the :doc:`built-in signal documentation </ref/signals>` for a complete list, +and a complete explanation of each signal. + +You can also `define and send your own custom signals`_; see below. + +.. _define and send your own custom signals: `defining and sending signals`_ + +Listening to signals +==================== + +To receive a signal, you need to register a *receiver* function that gets +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. + + :param weak: Django stores signal handlers as weak references by + default. Thus, if your receiver is a local function, it may be + garbage collected. To prevent this, pass ``weak=False`` when you call + the signal's ``connect()`` method. + + :param dispatch_uid: A unique identifier for a signal receiver in cases + where duplicate signals may be sent. See + :ref:`preventing-duplicate-signals` for more information. + +Let's see how this works by registering a signal that +gets called after each HTTP request is finished. We'll be connecting to the +:data:`~django.core.signals.request_finished` signal. + +.. _receiver-functions: + +Receiver functions +------------------ + +First, we need to define a receiver function. A receiver can be any Python +function or method: + +.. code-block:: python + + def my_callback(sender, **kwargs): + print "Request finished!" + +Notice that the function takes a ``sender`` argument, along with wildcard +keyword arguments (``**kwargs``); all signal handlers must take these arguments. + +We'll look at senders `a bit later`_, but right now look at the ``**kwargs`` +argument. All signals send keyword arguments, and may change those keyword +arguments at any time. In the case of +:data:`~django.core.signals.request_finished`, it's documented as sending no +arguments, which means we might be tempted to write our signal handling as +``my_callback(sender)``. + +.. _a bit later: `connecting to signals sent by specific senders`_ + +This would be wrong -- in fact, Django will throw an error if you do so. That's +because at any point arguments could get added to the signal and your receiver +must be able to handle those new arguments. + +.. _connecting-receiver-functions: + +Connecting receiver functions +----------------------------- + +Next, we'll need to connect our receiver to the signal: + +.. code-block:: python + + from django.core.signals import request_finished + + request_finished.connect(my_callback) + +Now, our ``my_callback`` function will be called each time a request finishes. + +.. admonition:: Where should this code live? + + You can put signal handling and registration code anywhere you like. + However, you'll need to make sure that the module it's in gets imported + early on so that the signal handling gets registered before any signals need + to be sent. This makes your app's ``models.py`` a good place to put + registration of signal handlers. + +.. _connecting-to-specific-signals: + +Connecting to signals sent by specific senders +---------------------------------------------- + +Some signals get sent many times, but you'll only be interested in receiving a +certain subset of those signals. For example, consider the +:data:`django.db.models.signals.pre_save` signal sent before a model gets saved. +Most of the time, you don't need to know when *any* model gets saved -- just +when one *specific* model is saved. + +In these cases, you can register to receive signals sent only by particular +senders. In the case of :data:`django.db.models.signals.pre_save`, the sender +will be the model class being saved, so you can indicate that you only want +signals sent by some model: + +.. code-block:: python + + from django.db.models.signals import pre_save + from myapp.models import MyModel + + def my_handler(sender, **kwargs): + ... + + pre_save.connect(my_handler, sender=MyModel) + +The ``my_handler`` function will only be called when an instance of ``MyModel`` +is saved. + +Different signals use different objects as their senders; you'll need to consult +the :doc:`built-in signal documentation </ref/signals>` for details of each +particular signal. + +.. _preventing-duplicate-signals: + +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. + +If this behavior is problematic (such as when using signals to +send an e-mail whenever a model is saved), pass a unique identifier as +the ``dispatch_uid`` argument to identify your receiver function. This +identifier will usually be a string, although any hashable object will +suffice. The end result is that your receiver function will only be +bound to the signal once for each unique ``dispatch_uid`` value. + +.. code-block:: python + + from django.core.signals import request_finished + + request_finished.connect(my_callback, dispatch_uid="my_unique_identifier") + +Defining and sending signals +============================ + +Your applications can take advantage of the signal infrastructure and provide +its own signals. + +Defining signals +---------------- + +.. class:: Signal([providing_args=list]) + +All signals are :class:`django.dispatch.Signal` instances. The +``providing_args`` is a list of the names of arguments the signal will provide +to listeners. + +For example: + +.. code-block:: python + + import django.dispatch + + pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"]) + +This declares a ``pizza_done`` signal that will provide receivers with +``toppings`` and ``size`` arguments. + +Remember that you're allowed to change this list of arguments at any time, so getting the API right on the first try isn't necessary. + +Sending signals +--------------- + +There are two ways to send send signals in Django. + +.. method:: Signal.send(sender, **kwargs) +.. method:: Signal.send_robust(sender, **kwargs) + +To send a signal, call either :meth:`Signal.send` or :meth:`Signal.send_robust`. +You must provide the ``sender`` argument, and may provide as many other keyword +arguments as you like. + +For example, here's how sending our ``pizza_done`` signal might look: + +.. code-block:: python + + class PizzaStore(object): + ... + + def send_pizza(self, toppings, size): + pizza_done.send(sender=self, toppings=toppings, size=size) + ... + +Both ``send()`` and ``send_robust()`` return a list of tuple pairs +``[(receiver, response), ... ]``, representing the list of called receiver +functions and their response values. + +``send()`` differs from ``send_robust()`` in how exceptions raised by receiver +functions are handled. ``send()`` does *not* catch any exceptions raised by +receivers; it simply allows errors to propagate. Thus not all receivers may +be notified of a signal in the face of an error. + +``send_robust()`` catches all errors derived from Python's ``Exception`` class, +and ensures all receivers are notified of the signal. If an error occurs, the +error instance is returned in the tuple pair for the receiver that raised the error. + +Disconnecting signals +===================== + +.. method:: Signal.disconnect([receiver=None, sender=None, weak=True, dispatch_uid=None]) + +To disconnect a receiver from a signal, call :meth:`Signal.disconnect`. The +arguments are as described in :meth:`.Signal.connect`. + +The *receiver* argument indicates the registered receiver to disconnect. It may +be ``None`` if ``dispatch_uid`` is used to identify the receiver. diff --git a/parts/django/docs/topics/templates.txt b/parts/django/docs/topics/templates.txt new file mode 100644 index 0000000..d249bd3 --- /dev/null +++ b/parts/django/docs/topics/templates.txt @@ -0,0 +1,617 @@ +============================ +The Django template language +============================ + +.. admonition:: About this document + + This document explains the language syntax of the Django template system. If + you're looking for a more technical perspective on how it works and how to + extend it, see :doc:`/ref/templates/api`. + +Django's template language is designed to strike a balance between power and +ease. It's designed to feel comfortable to those used to working with HTML. If +you have any exposure to other text-based template languages, such as Smarty_ +or CheetahTemplate_, you should feel right at home with Django's templates. + +.. admonition:: Philosophy + + If you have a background in programming, or if you're used to languages + like PHP which mix programming code directly into HTML, you'll want to + bear in mind that the Django template system is not simply Python embedded + into HTML. This is by design: the template system is meant to express + presentation, not program logic. + + The Django template system provides tags which function similarly to some + programming constructs -- an :ttag:`if` tag for boolean tests, a :ttag:`for` + tag for looping, etc. -- but these are not simply executed as the + corresponding Python code, and the template system will not execute + arbitrary Python expressions. Only the tags, filters and syntax listed below + are supported by default (although you can add :doc:`your own extensions + </howto/custom-template-tags>` to the template language as needed). + +.. _`The Django template language: For Python programmers`: ../templates_python/ +.. _Smarty: http://smarty.php.net/ +.. _CheetahTemplate: http://www.cheetahtemplate.org/ + +Templates +========= + +.. highlightlang:: html+django + +A template is simply a text file. It can generate any text-based format (HTML, +XML, CSV, etc.). + +A template contains **variables**, which get replaced with values when the +template is evaluated, and **tags**, which control the logic of the template. + +Below is a minimal template that illustrates a few basics. Each element will be +explained later in this document.:: + + {% extends "base_generic.html" %} + + {% block title %}{{ section.title }}{% endblock %} + + {% block content %} + <h1>{{ section.title }}</h1> + + {% for story in story_list %} + <h2> + <a href="{{ story.get_absolute_url }}"> + {{ story.headline|upper }} + </a> + </h2> + <p>{{ story.tease|truncatewords:"100" }}</p> + {% endfor %} + {% endblock %} + +.. admonition:: Philosophy + + Why use a text-based template instead of an XML-based one (like Zope's + TAL)? We wanted Django's template language to be usable for more than + just XML/HTML templates. At World Online, we use it for e-mails, + JavaScript and CSV. You can use the template language for any text-based + format. + + Oh, and one more thing: Making humans edit XML is sadistic! + +Variables +========= + +Variables look like this: ``{{ variable }}``. When the template engine +encounters a variable, it evaluates that variable and replaces it with the +result. + +Use a dot (``.``) to access attributes of a variable. + +.. admonition:: Behind the scenes + + Technically, when the template system encounters a dot, it tries the + following lookups, in this order: + + * Dictionary lookup + * Attribute lookup + * Method call + * List-index lookup + +In the above example, ``{{ section.title }}`` will be replaced with the +``title`` attribute of the ``section`` object. + +If you use a variable that doesn't exist, the template system will insert +the value of the ``TEMPLATE_STRING_IF_INVALID`` setting, which is set to ``''`` +(the empty string) by default. + +Filters +======= + +You can modify variables for display by using **filters**. + +Filters look like this: ``{{ name|lower }}``. This displays the value of the +``{{ name }}`` variable after being filtered through the ``lower`` filter, +which converts text to lowercase. Use a pipe (``|``) to apply a filter. + +Filters can be "chained." The output of one filter is applied to the next. +``{{ text|escape|linebreaks }}`` is a common idiom for escaping text contents, +then converting line breaks to ``<p>`` tags. + +Some filters take arguments. A filter argument looks like this: ``{{ +bio|truncatewords:30 }}``. This will display the first 30 words of the ``bio`` +variable. + +Filter arguments that contain spaces must be quoted; for example, to join a list +with commas and spaced you'd use ``{{ list|join:", " }}``. + +Django provides about thirty built-in template filters. You can read all about +them in the :ref:`built-in filter reference <ref-templates-builtins-filters>`. +To give you a taste of what's available, here are some of the more commonly used +template filters: + + :tfilter:`default` + If a variable is false or empty, use given default. Otherwise, use the + value of the variable + + For example:: + + {{ value|default:"nothing" }} + + If ``value`` isn't provided or is empty, the above will display + "``nothing``". + + :tfilter:`length` + Returns the length of the value. This works for both strings and lists; + for example:: + + {{ value|length }} + + If ``value`` is ``['a', 'b', 'c', 'd']``, the output will be ``4``. + + :tfilter:`striptags` + Strips all [X]HTML tags. For example:: + + {{ value|striptags }} + + If ``value`` is ``"<b>Joel</b> <button>is</button> a + <span>slug</span>"``, the output will be ``"Joel is a slug"``. + +Again, these are just a few examples; see the :ref:`built-in filter reference +<ref-templates-builtins-filters>` for the complete list. + +You can also create your own custom template filters; see +:doc:`/howto/custom-template-tags`. + +.. seealso:: + + Django's admin interface can include a complete reference of all template + tags and filters available for a given site. See + :doc:`/ref/contrib/admin/admindocs`. + +Tags +==== + +Tags look like this: ``{% tag %}``. Tags are more complex than variables: Some +create text in the output, some control flow by performing loops or logic, and +some load external information into the template to be used by later variables. + +Some tags require beginning and ending tags (i.e. ``{% tag %} ... tag contents +... {% endtag %}``). + +Django ships with about two dozen built-in template tags. You can read all about +them in the :ref:`built-in tag reference <ref-templates-builtins-tags>`. To give +you a taste of what's available, here are some of the more commonly used +tags: + + :ttag:`for` + Loop over each item in an array. For example, to display a list of athletes + provided in ``athlete_list``:: + + <ul> + {% for athlete in athlete_list %} + <li>{{ athlete.name }}</li> + {% endfor %} + </ul> + + :ttag:`if` and ``else`` + Evaluates a variable, and if that variable is "true" the contents of the + block are displayed:: + + {% if athlete_list %} + Number of athletes: {{ athlete_list|length }} + {% else %} + No athletes. + {% endif %} + + In the above, if ``athlete_list`` is not empty, the number of athletes + will be displayed by the ``{{ athlete_list|length }}`` variable. + + You can also use filters and various operators in the ``if`` tag:: + + {% if athlete_list|length > 1 %} + Team: {% for athlete in athlete_list %} ... {% endfor %} + {% else %} + Athlete: {{ athlete_list.0.name }} + {% endif %} + + :ttag:`block` and :ttag:`extends` + Set up `template inheritance`_ (see below), a powerful way + of cutting down on "boilerplate" in templates. + +Again, the above is only a selection of the whole list; see the :ref:`built-in +tag reference <ref-templates-builtins-tags>` for the complete list. + +You can also create your own custom template tags; see +:doc:`/howto/custom-template-tags`. + +.. seealso:: + + Django's admin interface can include a complete reference of all template + tags and filters available for a given site. See + :doc:`/ref/contrib/admin/admindocs`. + +Comments +======== + +To comment-out part of a line in a template, use the comment syntax: ``{# #}``. + +For example, this template would render as ``'hello'``:: + + {# greeting #}hello + +A comment can contain any template code, invalid or not. For example:: + + {# {% if foo %}bar{% else %} #} + +This syntax can only be used for single-line comments (no newlines are permitted +between the ``{#`` and ``#}`` delimiters). If you need to comment out a +multiline portion of the template, see the :ttag:`comment` tag. + +.. _template-inheritance: + +Template inheritance +==================== + +The most powerful -- and thus the most complex -- part of Django's template +engine is template inheritance. Template inheritance allows you to build a base +"skeleton" template that contains all the common elements of your site and +defines **blocks** that child templates can override. + +It's easiest to understand template inheritance by starting with an example:: + + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <link rel="stylesheet" href="style.css" /> + <title>{% block title %}My amazing site{% endblock %}</title> + </head> + + <body> + <div id="sidebar"> + {% block sidebar %} + <ul> + <li><a href="/">Home</a></li> + <li><a href="/blog/">Blog</a></li> + </ul> + {% endblock %} + </div> + + <div id="content"> + {% block content %}{% endblock %} + </div> + </body> + </html> + +This template, which we'll call ``base.html``, defines a simple HTML skeleton +document that you might use for a simple two-column page. It's the job of +"child" templates to fill the empty blocks with content. + +In this example, the ``{% block %}`` tag defines three blocks that child +templates can fill in. All the ``block`` tag does is to tell the template +engine that a child template may override those portions of the template. + +A child template might look like this:: + + {% extends "base.html" %} + + {% block title %}My amazing blog{% endblock %} + + {% block content %} + {% for entry in blog_entries %} + <h2>{{ entry.title }}</h2> + <p>{{ entry.body }}</p> + {% endfor %} + {% endblock %} + +The ``{% extends %}`` tag is the key here. It tells the template engine that +this template "extends" another template. When the template system evaluates +this template, first it locates the parent -- in this case, "base.html". + +At that point, the template engine will notice the three ``{% block %}`` tags +in ``base.html`` and replace those blocks with the contents of the child +template. Depending on the value of ``blog_entries``, the output might look +like:: + + <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> + <head> + <link rel="stylesheet" href="style.css" /> + <title>My amazing blog</title> + </head> + + <body> + <div id="sidebar"> + <ul> + <li><a href="/">Home</a></li> + <li><a href="/blog/">Blog</a></li> + </ul> + </div> + + <div id="content"> + <h2>Entry one</h2> + <p>This is my first entry.</p> + + <h2>Entry two</h2> + <p>This is my second entry.</p> + </div> + </body> + </html> + +Note that since the child template didn't define the ``sidebar`` block, the +value from the parent template is used instead. Content within a ``{% block %}`` +tag in a parent template is always used as a fallback. + +You can use as many levels of inheritance as needed. One common way of using +inheritance is the following three-level approach: + + * Create a ``base.html`` template that holds the main look-and-feel of your + site. + * Create a ``base_SECTIONNAME.html`` template for each "section" of your + site. For example, ``base_news.html``, ``base_sports.html``. These + templates all extend ``base.html`` and include section-specific + styles/design. + * Create individual templates for each type of page, such as a news + article or blog entry. These templates extend the appropriate section + template. + +This approach maximizes code reuse and makes it easy to add items to shared +content areas, such as section-wide navigation. + +Here are some tips for working with inheritance: + + * If you use ``{% extends %}`` in a template, it must be the first template + tag in that template. Template inheritance won't work, otherwise. + + * More ``{% block %}`` tags in your base templates are better. Remember, + child templates don't have to define all parent blocks, so you can fill + in reasonable defaults in a number of blocks, then only define the ones + you need later. It's better to have more hooks than fewer hooks. + + * If you find yourself duplicating content in a number of templates, it + probably means you should move that content to a ``{% block %}`` in a + parent template. + + * If you need to get the content of the block from the parent template, + the ``{{ block.super }}`` variable will do the trick. This is useful + if you want to add to the contents of a parent block instead of + completely overriding it. Data inserted using ``{{ block.super }}`` will + not be automatically escaped (see the `next section`_), since it was + already escaped, if necessary, in the parent template. + + * For extra readability, you can optionally give a *name* to your + ``{% endblock %}`` tag. For example:: + + {% block content %} + ... + {% endblock content %} + + In larger templates, this technique helps you see which ``{% block %}`` + tags are being closed. + +Finally, note that you can't define multiple ``{% block %}`` tags with the same +name in the same template. This limitation exists because a block tag works in +"both" directions. That is, a block tag doesn't just provide a hole to fill -- +it also defines the content that fills the hole in the *parent*. If there were +two similarly-named ``{% block %}`` tags in a template, that template's parent +wouldn't know which one of the blocks' content to use. + +.. _next section: #automatic-html-escaping +.. _automatic-html-escaping: + +Automatic HTML escaping +======================= + +.. versionadded:: 1.0 + +When generating HTML from templates, there's always a risk that a variable will +include characters that affect the resulting HTML. For example, consider this +template fragment:: + + Hello, {{ name }}. + +At first, this seems like a harmless way to display a user's name, but consider +what would happen if the user entered his name as this:: + + <script>alert('hello')</script> + +With this name value, the template would be rendered as:: + + Hello, <script>alert('hello')</script> + +...which means the browser would pop-up a JavaScript alert box! + +Similarly, what if the name contained a ``'<'`` symbol, like this? + + <b>username + +That would result in a rendered template like this:: + + Hello, <b>username + +...which, in turn, would result in the remainder of the Web page being bolded! + +Clearly, user-submitted data shouldn't be trusted blindly and inserted directly +into your Web pages, because a malicious user could use this kind of hole to +do potentially bad things. This type of security exploit is called a +`Cross Site Scripting`_ (XSS) attack. + +To avoid this problem, you have two options: + + * One, you can make sure to run each untrusted variable through the + ``escape`` filter (documented below), which converts potentially harmful + HTML characters to unharmful ones. This was the default solution + in Django for its first few years, but the problem is that it puts the + onus on *you*, the developer / template author, to ensure you're escaping + everything. It's easy to forget to escape data. + + * Two, you can take advantage of Django's automatic HTML escaping. The + remainder of this section describes how auto-escaping works. + +By default in Django, every template automatically escapes the output +of every variable tag. Specifically, these five characters are +escaped: + + * ``<`` is converted to ``<`` + * ``>`` is converted to ``>`` + * ``'`` (single quote) is converted to ``'`` + * ``"`` (double quote) is converted to ``"`` + * ``&`` is converted to ``&`` + +Again, we stress that this behavior is on by default. If you're using Django's +template system, you're protected. + +.. _Cross Site Scripting: http://en.wikipedia.org/wiki/Cross-site_scripting + +How to turn it off +------------------ + +If you don't want data to be auto-escaped, on a per-site, per-template level or +per-variable level, you can turn it off in several ways. + +Why would you want to turn it off? Because sometimes, template variables +contain data that you *intend* to be rendered as raw HTML, in which case you +don't want their contents to be escaped. For example, you might store a blob of +HTML in your database and want to embed that directly into your template. Or, +you might be using Django's template system to produce text that is *not* HTML +-- like an e-mail message, for instance. + +For individual variables +~~~~~~~~~~~~~~~~~~~~~~~~ + +To disable auto-escaping for an individual variable, use the ``safe`` filter:: + + This will be escaped: {{ data }} + This will not be escaped: {{ data|safe }} + +Think of *safe* as shorthand for *safe from further escaping* or *can be +safely interpreted as HTML*. In this example, if ``data`` contains ``'<b>'``, +the output will be:: + + This will be escaped: <b> + This will not be escaped: <b> + +For template blocks +~~~~~~~~~~~~~~~~~~~ + +To control auto-escaping for a template, wrap the template (or just a +particular section of the template) in the ``autoescape`` tag, like so:: + + {% autoescape off %} + Hello {{ name }} + {% endautoescape %} + +The ``autoescape`` tag takes either ``on`` or ``off`` as its argument. At +times, you might want to force auto-escaping when it would otherwise be +disabled. Here is an example template:: + + Auto-escaping is on by default. Hello {{ name }} + + {% autoescape off %} + This will not be auto-escaped: {{ data }}. + + Nor this: {{ other_data }} + {% autoescape on %} + Auto-escaping applies again: {{ name }} + {% endautoescape %} + {% endautoescape %} + +The auto-escaping tag passes its effect onto templates that extend the +current one as well as templates included via the ``include`` tag, just like +all block tags. For example:: + + # base.html + + {% autoescape off %} + <h1>{% block title %}{% endblock %}</h1> + {% block content %} + {% endblock %} + {% endautoescape %} + + + # child.html + + {% extends "base.html" %} + {% block title %}This & that{% endblock %} + {% block content %}{{ greeting }}{% endblock %} + +Because auto-escaping is turned off in the base template, it will also be +turned off in the child template, resulting in the following rendered +HTML when the ``greeting`` variable contains the string ``<b>Hello!</b>``:: + + <h1>This & that</h1> + <b>Hello!</b> + +Notes +----- + +Generally, template authors don't need to worry about auto-escaping very much. +Developers on the Python side (people writing views and custom filters) need to +think about the cases in which data shouldn't be escaped, and mark data +appropriately, so things Just Work in the template. + +If you're creating a template that might be used in situations where you're +not sure whether auto-escaping is enabled, then add an ``escape`` filter to any +variable that needs escaping. When auto-escaping is on, there's no danger of +the ``escape`` filter *double-escaping* data -- the ``escape`` filter does not +affect auto-escaped variables. + +String literals and automatic escaping +-------------------------------------- + +As we mentioned earlier, filter arguments can be strings:: + + {{ data|default:"This is a string literal." }} + +All string literals are inserted **without** any automatic escaping into the +template -- they act as if they were all passed through the ``safe`` filter. +The reasoning behind this is that the template author is in control of what +goes into the string literal, so they can make sure the text is correctly +escaped when the template is written. + +This means you would write :: + + {{ data|default:"3 < 2" }} + +...rather than :: + + {{ data|default:"3 < 2" }} <-- Bad! Don't do this. + +This doesn't affect what happens to data coming from the variable itself. +The variable's contents are still automatically escaped, if necessary, because +they're beyond the control of the template author. + +.. _loading-custom-template-libraries: + +Custom tag and filter libraries +=============================== + +Certain applications provide custom tag and filter libraries. To access them in +a template, use the ``{% load %}`` tag:: + + {% load comments %} + + {% comment_form for blogs.entries entry.id with is_public yes %} + +In the above, the ``load`` tag loads the ``comments`` tag library, which then +makes the ``comment_form`` tag available for use. Consult the documentation +area in your admin to find the list of custom libraries in your installation. + +The ``{% load %}`` tag can take multiple library names, separated by spaces. +Example:: + + {% load comments i18n %} + +See :doc:`/howto/custom-template-tags` for information on writing your own custom +template libraries. + +Custom libraries and template inheritance +----------------------------------------- + +When you load a custom tag or filter library, the tags/filters are only made +available to the current template -- not any parent or child templates along +the template-inheritance path. + +For example, if a template ``foo.html`` has ``{% load comments %}``, a child +template (e.g., one that has ``{% extends "foo.html" %}``) will *not* have +access to the comments template tags and filters. The child template is +responsible for its own ``{% load comments %}``. + +This is a feature for the sake of maintainability and sanity. diff --git a/parts/django/docs/topics/testing.txt b/parts/django/docs/topics/testing.txt new file mode 100644 index 0000000..155f758 --- /dev/null +++ b/parts/django/docs/topics/testing.txt @@ -0,0 +1,1613 @@ +=========================== +Testing Django applications +=========================== + +.. module:: django.test + :synopsis: Testing tools for Django applications. + +Automated testing is an extremely useful bug-killing tool for the modern +Web developer. You can use a collection of tests -- a **test suite** -- to +solve, or avoid, a number of problems: + + * When you're writing new code, you can use tests to validate your code + works as expected. + + * When you're refactoring or modifying old code, you can use tests to + ensure your changes haven't affected your application's behavior + unexpectedly. + +Testing a Web application is a complex task, because a Web application is made +of several layers of logic -- from HTTP-level request handling, to form +validation and processing, to template rendering. With Django's test-execution +framework and assorted utilities, you can simulate requests, insert test data, +inspect your application's output and generally verify your code is doing what +it should be doing. + +The best part is, it's really easy. + +This document is split into two primary sections. First, we explain how to +write tests with Django. Then, we explain how to run them. + +Writing tests +============= + +There are two primary ways to write tests with Django, corresponding to the +two test frameworks that ship in the Python standard library. The two +frameworks are: + + * **Doctests** -- tests that are embedded in your functions' docstrings and + are written in a way that emulates a session of the Python interactive + interpreter. For example:: + + def my_func(a_list, idx): + """ + >>> a = ['larry', 'curly', 'moe'] + >>> my_func(a, 0) + 'larry' + >>> my_func(a, 1) + 'curly' + """ + return a_list[idx] + + * **Unit tests** -- tests that are expressed as methods on a Python class + that subclasses ``unittest.TestCase``. For example:: + + import unittest + + class MyFuncTestCase(unittest.TestCase): + def testBasic(self): + a = ['larry', 'curly', 'moe'] + self.assertEquals(my_func(a, 0), 'larry') + self.assertEquals(my_func(a, 1), 'curly') + +You can choose the test framework you like, depending on which syntax you +prefer, or you can mix and match, using one framework for some of your code and +the other framework for other code. You can also use any *other* Python test +frameworks, as we'll explain in a bit. + +Writing doctests +---------------- + +Doctests use Python's standard doctest_ module, which searches your docstrings +for statements that resemble a session of the Python interactive interpreter. +A full explanation of how doctest works is out of the scope of this document; +read Python's official documentation for the details. + +.. admonition:: What's a **docstring**? + + A good explanation of docstrings (and some guidelines for using them + effectively) can be found in :pep:`257`: + + A docstring is a string literal that occurs as the first statement in + a module, function, class, or method definition. Such a docstring + becomes the ``__doc__`` special attribute of that object. + + For example, this function has a docstring that describes what it does:: + + def add_two(num): + "Return the result of adding two to the provided number." + return num + 2 + + Because tests often make great documentation, putting tests directly in + your docstrings is an effective way to document *and* test your code. + +For a given Django application, the test runner looks for doctests in two +places: + + * The ``models.py`` file. You can define module-level doctests and/or a + doctest for individual models. It's common practice to put + application-level doctests in the module docstring and model-level + doctests in the model docstrings. + + * A file called ``tests.py`` in the application directory -- i.e., the + directory that holds ``models.py``. This file is a hook for any and all + doctests you want to write that aren't necessarily related to models. + +Here is an example model doctest:: + + # models.py + + from django.db import models + + class Animal(models.Model): + """ + An animal that knows how to make noise + + # Create some animals + >>> lion = Animal.objects.create(name="lion", sound="roar") + >>> cat = Animal.objects.create(name="cat", sound="meow") + + # Make 'em speak + >>> lion.speak() + 'The lion says "roar"' + >>> cat.speak() + 'The cat says "meow"' + """ + name = models.CharField(max_length=20) + sound = models.CharField(max_length=20) + + def speak(self): + return 'The %s says "%s"' % (self.name, self.sound) + +When you :ref:`run your tests <running-tests>`, the test runner will find this +docstring, notice that portions of it look like an interactive Python session, +and execute those lines while checking that the results match. + +In the case of model tests, note that the test runner takes care of creating +its own test database. That is, any test that accesses a database -- by +creating and saving model instances, for example -- will not affect your +production database. However, the database is not refreshed between doctests, +so if your doctest requires a certain state you should consider flushing the +database or loading a fixture. (See the section on fixtures, below, for more +on this.) Note that to use this feature, the database user Django is connecting +as must have ``CREATE DATABASE`` rights. + +For more details about how doctest works, see the `standard library +documentation for doctest`_. + +.. _doctest: http://docs.python.org/library/doctest.html +.. _standard library documentation for doctest: doctest_ + +Writing unit tests +------------------ + +Like doctests, Django's unit tests use a standard library module: unittest_. +This module uses a different way of defining tests, taking a class-based +approach. + +As with doctests, for a given Django application, the test runner looks for +unit tests in two places: + + * The ``models.py`` file. The test runner looks for any subclass of + ``unittest.TestCase`` in this module. + + * A file called ``tests.py`` in the application directory -- i.e., the + directory that holds ``models.py``. Again, the test runner looks for any + subclass of ``unittest.TestCase`` in this module. + +This example ``unittest.TestCase`` subclass is equivalent to the example given +in the doctest section above:: + + import unittest + from myapp.models import Animal + + class AnimalTestCase(unittest.TestCase): + def setUp(self): + self.lion = Animal.objects.create(name="lion", sound="roar") + self.cat = Animal.objects.create(name="cat", sound="meow") + + def testSpeaking(self): + self.assertEquals(self.lion.speak(), 'The lion says "roar"') + self.assertEquals(self.cat.speak(), 'The cat says "meow"') + +When you :ref:`run your tests <running-tests>`, the default behavior of the +test utility is to find all the test cases (that is, subclasses of +``unittest.TestCase``) in ``models.py`` and ``tests.py``, automatically build a +test suite out of those test cases, and run that suite. + +There is a second way to define the test suite for a module: if you define a +function called ``suite()`` in either ``models.py`` or ``tests.py``, the +Django test runner will use that function to construct the test suite for that +module. This follows the `suggested organization`_ for unit tests. See the +Python documentation for more details on how to construct a complex test +suite. + +For more details about ``unittest``, see the `standard library unittest +documentation`_. + +.. _unittest: http://docs.python.org/library/unittest.html +.. _standard library unittest documentation: unittest_ +.. _suggested organization: http://docs.python.org/library/unittest.html#organizing-tests + +Which should I use? +------------------- + +Because Django supports both of the standard Python test frameworks, it's up to +you and your tastes to decide which one to use. You can even decide to use +*both*. + +For developers new to testing, however, this choice can seem confusing. Here, +then, are a few key differences to help you decide which approach is right for +you: + + * If you've been using Python for a while, ``doctest`` will probably feel + more "pythonic". It's designed to make writing tests as easy as possible, + so it requires no overhead of writing classes or methods. You simply put + tests in docstrings. This has the added advantage of serving as + documentation (and correct documentation, at that!). + + If you're just getting started with testing, using doctests will probably + get you started faster. + + * The ``unittest`` framework will probably feel very familiar to developers + coming from Java. ``unittest`` is inspired by Java's JUnit, so you'll + feel at home with this method if you've used JUnit or any test framework + inspired by JUnit. + + * If you need to write a bunch of tests that share similar code, then + you'll appreciate the ``unittest`` framework's organization around + classes and methods. This makes it easy to abstract common tasks into + common methods. The framework also supports explicit setup and/or cleanup + routines, which give you a high level of control over the environment + in which your test cases are run. + +Again, remember that you can use both systems side-by-side (even in the same +app). In the end, most projects will eventually end up using both. Each shines +in different circumstances. + +.. _running-tests: + +Running tests +============= + +Once you've written tests, run them using the :djadmin:`test` command of +your project's ``manage.py`` utility:: + + $ ./manage.py test + +By default, this will run every test in every application in +:setting:`INSTALLED_APPS`. If you only want to run tests for a particular +application, add the application name to the command line. For example, if your +:setting:`INSTALLED_APPS` contains ``'myproject.polls'`` and +``'myproject.animals'``, you can run the ``myproject.animals`` unit tests alone +with this command:: + + $ ./manage.py test animals + +Note that we used ``animals``, not ``myproject.animals``. + +.. versionadded:: 1.0 + You can now choose which test to run. + +You can be even *more* specific by naming an individual test case. To +run a single test case in an application (for example, the +``AnimalTestCase`` described in the "Writing unit tests" section), add +the name of the test case to the label on the command line:: + + $ ./manage.py test animals.AnimalTestCase + +And it gets even more granular than that! To run a *single* test +method inside a test case, add the name of the test method to the +label:: + + $ ./manage.py test animals.AnimalTestCase.testFluffyAnimals + +.. 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 +class with a class-level doctest, you can invoke that test by appending the +name of the test method or class to the label:: + + $ ./manage.py test animals.classify + +If you want to run the doctest for a specific method in a class, add the +name of the method to the label:: + + $ ./manage.py test animals.Classifier.run + +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 +failures, report on how many tests were run and how many errors and failures +were encountered, and destroy any test databases as usual. Thus pressing +``Ctrl-C`` can be very useful if you forget to pass the :djadminopt:`--failfast` +option, notice that some tests are unexpectedly failing, and want to get details +on the failures without waiting for the full test run to complete. + +If you do not want to wait for the currently running test to finish, you +can press ``Ctrl-C`` a second time and the test run will halt immediately, +but not gracefully. No details of the tests run before the interruption will +be reported, and any test databases created by the run will not be destroyed. + +.. admonition:: Test with warnings enabled + + It is a good idea to run your tests with ``python -Wall manage.py + test``. This will allow you to catch any deprecation warnings that + might be in your code. Django (as well as many other libraries) use + warnings to flag when features are deprecated. It can also flag + areas in your code that are not strictly wrong, but may benefit + from a better implementation. + +Running tests outside the test runner +------------------------------------- + +If you want to run tests outside of ``./manage.py test`` -- for example, +from a shell prompt -- you will need to set up the test +environment first. Django provides a convenience method to do this:: + + >>> from django.test.utils import setup_test_environment + >>> setup_test_environment() + +This convenience method sets up the test database, and puts other +Django features into modes that allow for repeatable testing. + +The call to :meth:`~django.test.utils.setup_test_environment` is made +automatically as part of the setup of `./manage.py test`. You only +need to manually invoke this method if you're not using running your +tests via Django's test runner. + +The test database +----------------- + +Tests that require a database (namely, model tests) will not use your "real" +(production) database. Separate, blank databases are created for the tests. + +Regardless of whether the tests pass or fail, the test databases are destroyed +when all the tests have been executed. + +By default the test databases get their names by prepending ``test_`` +to the value of the :setting:`NAME` settings for the databases +defined in :setting:`DATABASES`. When using the SQLite database engine +the tests will by default use an in-memory database (i.e., the +database will be created in memory, bypassing the filesystem +entirely!). If you want to use a different database name, specify +:setting:`TEST_NAME` in the dictionary for any given database in +:setting:`DATABASES`. + +Aside from using a separate database, the test runner will otherwise +use all of the same database settings you have in your settings file: +:setting:`ENGINE`, :setting:`USER`, :setting:`HOST`, etc. The test +database is created by the user specified by ``USER``, so you'll need +to make sure that the given user account has sufficient privileges to +create a new database on the system. + +.. versionadded:: 1.0 + +For fine-grained control over the character encoding of your test +database, use the :setting:`TEST_CHARSET` option. If you're using +MySQL, you can also use the :setting:`TEST_COLLATION` option to +control the particular collation used by the test database. See the +:doc:`settings documentation </ref/settings>` for details of these +advanced settings. + +.. _topics-testing-masterslave: + +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, +and as a result, data created on the master won't be seen on the +slave. + +To compensate for this, Django allows you to define that a database is +a *test mirror*. Consider the following (simplified) example database +configuration:: + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'myproject', + 'HOST': 'dbmaster', + # ... plus some other settings + }, + 'slave': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'myproject', + 'HOST': 'dbslave', + 'TEST_MIRROR': 'default' + # ... plus some other settings + } + } + +In this setup, we have two database servers: ``dbmaster``, described +by the database alias ``default``, and ``dbslave`` described by the +alias ``slave``. As you might expect, ``dbslave`` has been configured +by the database administrator as a read slave of ``dbmaster``, so in +normal activity, any write to ``default`` will appear on ``slave``. + +If Django created two independent test databases, this would break any +tests that expected replication to occur. However, the ``slave`` +database has been configured as a test mirror (using the +:setting:`TEST_MIRROR` setting), indicating that under testing, +``slave`` should be treated as a mirror of ``default``. + +When the test environment is configured, a test version of ``slave`` +will *not* be created. Instead the connection to ``slave`` +will be redirected to point at ``default``. As a result, writes to +``default`` will appear on ``slave`` -- but because they are actually +the same database, not because there is data replication between the +two databases. + +.. _topics-testing-creation-dependencies: + +Controlling creation order for test databases +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.2.4 + +By default, Django will always create the ``default`` database first. +However, no guarantees are made on the creation order of any other +databases in your test setup. + +If your database configuration requires a specific creation order, you +can specify the dependencies that exist using the +:setting:`TEST_DEPENDENCIES` setting. Consider the following +(simplified) example database configuration:: + + DATABASES = { + 'default': { + # ... db settings + 'TEST_DEPENDENCIES': ['diamonds'] + }, + 'diamonds': { + # ... db settings + }, + 'clubs': { + # ... db settings + 'TEST_DEPENDENCIES': ['diamonds'] + }, + 'spades': { + # ... db settings + 'TEST_DEPENDENCIES': ['diamonds','hearts'] + }, + 'hearts': { + # ... db settings + 'TEST_DEPENDENCIES': ['diamonds','clubs'] + } + } + +Under this configuration, the ``diamonds`` database will be created first, +as it is the only database alias without dependencies. The ``default``` and +``clubs`` alias will be created next (although the order of creation of this +pair is not guaranteed); then ``hearts``; and finally ``spades``. + +If there are any circular dependencies in the +:setting:`TEST_DEPENDENCIES` definition, an ``ImproperlyConfigured`` +exception will be raised. + +Other test conditions +--------------------- + +Regardless of the value of the :setting:`DEBUG` setting in your configuration +file, all Django tests run with :setting:`DEBUG`\=False. This is to ensure that +the observed output of your code matches what will be seen in a production +setting. + +Understanding the test output +----------------------------- + +When you run your tests, you'll see a number of messages as the test runner +prepares itself. You can control the level of detail of these messages with the +``verbosity`` option on the command line:: + + Creating test database... + Creating table myapp_animal + Creating table myapp_mineral + Loading 'initial_data' fixtures... + No fixtures found. + +This tells you that the test runner is creating a test database, as described +in the previous section. + +Once the test database has been created, Django will run your tests. +If everything goes well, you'll see something like this:: + + ---------------------------------------------------------------------- + Ran 22 tests in 0.221s + + OK + +If there are test failures, however, you'll see full details about which tests +failed:: + + ====================================================================== + FAIL: Doctest: ellington.core.throttle.models + ---------------------------------------------------------------------- + Traceback (most recent call last): + File "/dev/django/test/doctest.py", line 2153, in runTest + raise self.failureException(self.format_failure(new.getvalue())) + AssertionError: Failed doctest test for myapp.models + File "/dev/myapp/models.py", line 0, in models + + ---------------------------------------------------------------------- + File "/dev/myapp/models.py", line 14, in myapp.models + Failed example: + throttle.check("actor A", "action one", limit=2, hours=1) + Expected: + True + Got: + False + + ---------------------------------------------------------------------- + Ran 2 tests in 0.048s + + FAILED (failures=1) + +A full explanation of this error output is beyond the scope of this document, +but it's pretty intuitive. You can consult the documentation of Python's +``unittest`` library for details. + +Note that the return code for the test-runner script is the total number of +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. + +Testing tools +============= + +Django provides a small set of tools that come in handy when writing tests. + +The test client +--------------- + +.. module:: django.test.client + :synopsis: Django's test client. + +The test client is a Python class that acts as a dummy Web browser, allowing +you to test your views and interact with your Django-powered application +programmatically. + +Some of the things you can do with the test client are: + + * Simulate GET and POST requests on a URL and observe the response -- + everything from low-level HTTP (result headers and status codes) to + page content. + + * Test that the correct view is executed for a given URL. + + * Test that a given request is rendered by a given Django template, with + a template context that contains certain values. + +Note that the test client is not intended to be a replacement for Twill_, +Selenium_, or other "in-browser" frameworks. Django's test client has +a different focus. In short: + + * Use Django's test client to establish that the correct view is being + called and that the view is collecting the correct context data. + + * Use in-browser frameworks such as Twill and Selenium to test *rendered* + HTML and the *behavior* of Web pages, namely JavaScript functionality. + +A comprehensive test suite should use a combination of both test types. + +.. _Twill: http://twill.idyll.org/ +.. _Selenium: http://seleniumhq.org/ + +Overview and a quick example +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To use the test client, instantiate ``django.test.client.Client`` and retrieve +Web pages:: + + >>> from django.test.client import Client + >>> c = Client() + >>> response = c.post('/login/', {'username': 'john', 'password': 'smith'}) + >>> response.status_code + 200 + >>> response = c.get('/customer/details/') + >>> response.content + '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 ...' + +As this example suggests, you can instantiate ``Client`` from within a session +of the Python interactive interpreter. + +Note a few important things about how the test client works: + + * The test client does *not* require the Web server to be running. In fact, + it will run just fine with no Web server running at all! That's because + it avoids the overhead of HTTP and deals directly with the Django + framework. This helps make the unit tests run quickly. + + * When retrieving pages, remember to specify the *path* of the URL, not the + whole domain. For example, this is correct:: + + >>> c.get('/login/') + + This is incorrect:: + + >>> c.get('http://www.example.com/login/') + + The test client is not capable of retrieving Web pages that are not + powered by your Django project. If you need to retrieve other Web pages, + use a Python standard library module such as urllib_ or urllib2_. + + * To resolve URLs, the test client uses whatever URLconf is pointed-to by + your :setting:`ROOT_URLCONF` setting. + + * Although the above example would work in the Python interactive + interpreter, some of the test client's functionality, notably the + template-related functionality, is only available *while tests are + running*. + + The reason for this is that Django's test runner performs a bit of black + magic in order to determine which template was loaded by a given view. + This black magic (essentially a patching of Django's template system in + memory) only happens during test running. + + * 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 + ``enforce_csrf_checks`` argument when you construct your + client:: + + >>> from django.test import Client + >>> csrf_client = Client(enforce_csrf_checks=True) + + +.. _urllib: http://docs.python.org/library/urllib.html +.. _urllib2: http://docs.python.org/library/urllib2.html + +Making requests +~~~~~~~~~~~~~~~ + +Use the ``django.test.client.Client`` class to make requests. It requires no +arguments at time of construction: + +.. class:: Client() + + Once you have a ``Client`` instance, you can call any of the following + methods: + + .. method:: Client.get(path, data={}, follow=False, **extra) + + + Makes a GET request on the provided ``path`` and returns a ``Response`` + object, which is documented below. + + The key-value pairs in the ``data`` dictionary are used to create a GET + data payload. For example:: + + >>> c = Client() + >>> c.get('/customers/details/', {'name': 'fred', 'age': 7}) + + ...will result in the evaluation of a GET request equivalent to:: + + /customers/details/?name=fred&age=7 + + The ``extra`` keyword arguments parameter can be used to specify + headers to be sent in the request. For example:: + + >>> c = Client() + >>> c.get('/customers/details/', {'name': 'fred', 'age': 7}, + ... HTTP_X_REQUESTED_WITH='XMLHttpRequest') + + ...will send the HTTP header ``HTTP_X_REQUESTED_WITH`` to the + details view, which is a good way to test code paths that use the + :meth:`django.http.HttpRequest.is_ajax()` method. + + .. versionadded:: 1.1 + + If you already have the GET arguments in URL-encoded form, you can + use that encoding instead of using the data argument. For example, + the previous GET request could also be posed as:: + + >>> c = Client() + >>> c.get('/customers/details/?name=fred&age=7') + + If you provide a URL with both an encoded GET data and a data argument, + the data argument will take precedence. + + If you set ``follow`` to ``True`` the client will follow any redirects + and a ``redirect_chain`` attribute will be set in the response object + containing tuples of the intermediate urls and status codes. + + If you had an url ``/redirect_me/`` that redirected to ``/next/``, that + redirected to ``/final/``, this is what you'd see:: + + >>> response = c.get('/redirect_me/', follow=True) + >>> response.redirect_chain + [(u'http://testserver/next/', 302), (u'http://testserver/final/', 302)] + + .. method:: Client.post(path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra) + + Makes a POST request on the provided ``path`` and returns a + ``Response`` object, which is documented below. + + The key-value pairs in the ``data`` dictionary are used to submit POST + data. For example:: + + >>> c = Client() + >>> c.post('/login/', {'name': 'fred', 'passwd': 'secret'}) + + ...will result in the evaluation of a POST request to this URL:: + + /login/ + + ...with this POST data:: + + name=fred&passwd=secret + + If you provide ``content_type`` (e.g., ``text/xml`` for an XML + payload), the contents of ``data`` will be sent as-is in the POST + request, using ``content_type`` in the HTTP ``Content-Type`` header. + + If you don't provide a value for ``content_type``, the values in + ``data`` will be transmitted with a content type of + ``multipart/form-data``. In this case, the key-value pairs in ``data`` + will be encoded as a multipart message and used to create the POST data + payload. + + To submit multiple values for a given key -- for example, to specify + the selections for a ``<select multiple>`` -- provide the values as a + list or tuple for the required key. For example, this value of ``data`` + would submit three selected values for the field named ``choices``:: + + {'choices': ('a', 'b', 'd')} + + Submitting files is a special case. To POST a file, you need only + provide the file field name as a key, and a file handle to the file you + wish to upload as a value. For example:: + + >>> c = Client() + >>> f = open('wishlist.doc') + >>> c.post('/customers/wishes/', {'name': 'fred', 'attachment': f}) + >>> f.close() + + (The name ``attachment`` here is not relevant; use whatever name your + file-processing code expects.) + + Note that if you wish to use the same file handle for multiple + ``post()`` calls then you will need to manually reset the file + pointer between posts. The easiest way to do this is to + manually close the file after it has been provided to + ``post()``, as demonstrated above. + + You should also ensure that the file is opened in a way that + allows the data to be read. If your file contains binary data + such as an image, this means you will need to open the file in + ``rb`` (read binary) mode. + + The ``extra`` argument acts the same as for :meth:`Client.get`. + + .. versionchanged:: 1.1 + + If the URL you request with a POST contains encoded parameters, these + parameters will be made available in the request.GET data. For example, + if you were to make the request:: + + >>> c.post('/login/?visitor=true', {'name': 'fred', 'passwd': 'secret'}) + + ... the view handling this request could interrogate request.POST + to retrieve the username and password, and could interrogate request.GET + to determine if the user was a visitor. + + If you set ``follow`` to ``True`` the client will follow any redirects + and a ``redirect_chain`` attribute will be set in the response object + containing tuples of the intermediate urls and status codes. + + .. method:: Client.head(path, data={}, follow=False, **extra) + + .. versionadded:: 1.1 + + Makes a HEAD request on the provided ``path`` and returns a ``Response`` + object. Useful for testing RESTful interfaces. Acts just like + :meth:`Client.get` except it does not return a message body. + + If you set ``follow`` to ``True`` the client will follow any redirects + and a ``redirect_chain`` attribute will be set in the response object + containing tuples of the intermediate urls and status codes. + + .. method:: Client.options(path, data={}, follow=False, **extra) + + .. versionadded:: 1.1 + + Makes an OPTIONS request on the provided ``path`` and returns a + ``Response`` object. Useful for testing RESTful interfaces. + + If you set ``follow`` to ``True`` the client will follow any redirects + and a ``redirect_chain`` attribute will be set in the response object + containing tuples of the intermediate urls and status codes. + + The ``extra`` argument acts the same as for :meth:`Client.get`. + + .. method:: Client.put(path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra) + + .. versionadded:: 1.1 + + Makes a PUT request on the provided ``path`` and returns a + ``Response`` object. Useful for testing RESTful interfaces. Acts just + like :meth:`Client.post` except with the PUT request method. + + If you set ``follow`` to ``True`` the client will follow any redirects + and a ``redirect_chain`` attribute will be set in the response object + containing tuples of the intermediate urls and status codes. + + .. method:: Client.delete(path, follow=False, **extra) + + .. versionadded:: 1.1 + + Makes an DELETE request on the provided ``path`` and returns a + ``Response`` object. Useful for testing RESTful interfaces. + + If you set ``follow`` to ``True`` the client will follow any redirects + and a ``redirect_chain`` attribute will be set in the response object + containing tuples of the intermediate urls and status codes. + + The ``extra`` argument acts the same as for :meth:`Client.get`. + + .. method:: Client.login(**credentials) + + .. versionadded:: 1.0 + + If your site uses Django's :doc:`authentication system</topics/auth>` + and you deal with logging in users, you can use the test client's + ``login()`` method to simulate the effect of a user logging into the + site. + + After you call this method, the test client will have all the cookies + and session data required to pass any login-based tests that may form + part of a view. + + The format of the ``credentials`` argument depends on which + :ref:`authentication backend <authentication-backends>` you're using + (which is configured by your :setting:`AUTHENTICATION_BACKENDS` + setting). If you're using the standard authentication backend provided + by Django (``ModelBackend``), ``credentials`` should be the user's + username and password, provided as keyword arguments:: + + >>> c = Client() + >>> c.login(username='fred', password='secret') + + # Now you can access a view that's only available to logged-in users. + + If you're using a different authentication backend, this method may + require different credentials. It requires whichever credentials are + required by your backend's ``authenticate()`` method. + + ``login()`` returns ``True`` if it the credentials were accepted and + login was successful. + + Finally, you'll need to remember to create user accounts before you can + use this method. As we explained above, the test runner is executed + using a test database, which contains no users by default. As a result, + user accounts that are valid on your production site will not work + under test conditions. You'll need to create users as part of the test + suite -- either manually (using the Django model API) or with a test + fixture. Remember that if you want your test user to have a password, + you can't set the user's password by setting the password attribute + directly -- you must use the + :meth:`~django.contrib.auth.models.User.set_password()` function to + store a correctly hashed password. Alternatively, you can use the + :meth:`~django.contrib.auth.models.UserManager.create_user` helper + method to create a new user with a correctly hashed password. + + .. method:: Client.logout() + + .. versionadded:: 1.0 + + If your site uses Django's :doc:`authentication system</topics/auth>`, + the ``logout()`` method can be used to simulate the effect of a user + logging out of your site. + + After you call this method, the test client will have all the cookies + and session data cleared to defaults. Subsequent requests will appear + to come from an AnonymousUser. + +Testing responses +~~~~~~~~~~~~~~~~~ + +The ``get()`` and ``post()`` methods both return a ``Response`` object. This +``Response`` object is *not* the same as the ``HttpResponse`` object returned +Django views; the test response object has some additional data useful for +test code to verify. + +Specifically, a ``Response`` object has the following attributes: + +.. class:: Response() + + .. attribute:: client + + The test client that was used to make the request that resulted in the + response. + + .. attribute:: content + + The body of the response, as a string. This is the final page content as + rendered by the view, or any error message. + + .. attribute:: context + + The template ``Context`` instance that was used to render the template that + produced the response content. + + If the rendered page used multiple templates, then ``context`` will be a + list of ``Context`` objects, in the order in which they were rendered. + + .. versionadded:: 1.1 + + Regardless of the number of templates used during rendering, you can + retrieve context values using the ``[]`` operator. For example, the + context variable ``name`` could be retrieved using:: + + >>> response = client.get('/foo/') + >>> response.context['name'] + 'Arthur' + + .. attribute:: request + + The request data that stimulated the response. + + .. attribute:: status_code + + The HTTP status of the response, as an integer. See RFC2616_ for a full + list of HTTP status codes. + + .. attribute:: template + + The ``Template`` instance that was used to render the final content. Use + ``template.name`` to get the template's file name, if the template was + loaded from a file. (The name is a string such as ``'admin/index.html'``.) + + If the rendered page used multiple templates -- e.g., using :ref:`template + inheritance<template-inheritance>` -- then ``template`` will be a list of + ``Template`` instances, in the order in which they were rendered. + +You can also use dictionary syntax on the response object to query the value +of any settings in the HTTP headers. For example, you could determine the +content type of a response using ``response['Content-Type']``. + +.. _RFC2616: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + +Exceptions +~~~~~~~~~~ + +If you point the test client at a view that raises an exception, that exception +will be visible in the test case. You can then use a standard ``try...except`` +block or ``unittest.TestCase.assertRaises()`` to test for exceptions. + +The only exceptions that are not visible to the test client are ``Http404``, +``PermissionDenied`` and ``SystemExit``. Django catches these exceptions +internally and converts them into the appropriate HTTP response codes. In these +cases, you can check ``response.status_code`` in your test. + +Persistent state +~~~~~~~~~~~~~~~~ + +The test client is stateful. If a response returns a cookie, then that cookie +will be stored in the test client and sent with all subsequent ``get()`` and +``post()`` requests. + +Expiration policies for these cookies are not followed. If you want a cookie +to expire, either delete it manually or create a new ``Client`` instance (which +will effectively delete all cookies). + +A test client has two attributes that store persistent state information. You +can access these properties as part of a test condition. + +.. attribute:: Client.cookies + + A Python ``SimpleCookie`` object, containing the current values of all the + client cookies. See the `Cookie module documentation`_ for more. + +.. attribute:: Client.session + + A dictionary-like object containing session information. See the + :doc:`session documentation</topics/http/sessions>` for full details. + + To modify the session and then save it, it must be stored in a variable + first (because a new ``SessionStore`` is created every time this property + is accessed):: + + def test_something(self): + session = self.client.session + session['somekey'] = 'test' + session.save() + +.. _Cookie module documentation: http://docs.python.org/library/cookie.html + +Example +~~~~~~~ + +The following is a simple unit test using the test client:: + + import unittest + from django.test.client import Client + + class SimpleTest(unittest.TestCase): + def setUp(self): + # Every test needs a client. + self.client = Client() + + def test_details(self): + # Issue a GET request. + response = self.client.get('/customer/details/') + + # Check that the response is 200 OK. + self.failUnlessEqual(response.status_code, 200) + + # Check that the rendered context contains 5 customers. + self.failUnlessEqual(len(response.context['customers']), 5) + +TestCase +-------- + +.. currentmodule:: django.test + +Normal Python unit test classes extend a base class of ``unittest.TestCase``. +Django provides an extension of this base class: + +.. class:: TestCase() + +This class provides some additional capabilities that can be useful for testing +Web sites. + +Converting a normal ``unittest.TestCase`` to a Django ``TestCase`` is 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. + +.. versionadded:: 1.1 + +.. class:: TransactionTestCase() + +Django ``TestCase`` classes make use of database transaction facilities, if +available, to speed up the process of resetting the database to a known state +at the beginning of each test. A consequence of this, however, is that the +effects of transaction commit and rollback cannot be tested by a Django +``TestCase`` class. If your test requires testing of such transactional +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. + +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. + +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:: + 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. + + +Default test client +~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.0 + +.. attribute:: TestCase.client + +Every test case in a ``django.test.TestCase`` instance has access to an +instance of a Django test client. This client can be accessed as +``self.client``. This client is recreated for each test, so you don't have to +worry about state (such as cookies) carrying over from one test to another. + +This means, instead of instantiating a ``Client`` in each test:: + + import unittest + from django.test.client import Client + + class SimpleTest(unittest.TestCase): + def test_details(self): + client = Client() + response = client.get('/customer/details/') + self.failUnlessEqual(response.status_code, 200) + + def test_index(self): + client = Client() + response = client.get('/customer/index/') + self.failUnlessEqual(response.status_code, 200) + +...you can just refer to ``self.client``, like so:: + + from django.test import TestCase + + class SimpleTest(TestCase): + def test_details(self): + response = self.client.get('/customer/details/') + self.failUnlessEqual(response.status_code, 200) + + def test_index(self): + response = self.client.get('/customer/index/') + self.failUnlessEqual(response.status_code, 200) + +.. _topics-testing-fixtures: + +Fixture loading +~~~~~~~~~~~~~~~ + +.. attribute:: TestCase.fixtures + +A test case for a database-backed Web site isn't much use if there isn't any +data in the database. To make it easy to put test data into the database, +Django's custom ``TestCase`` class provides a way of loading **fixtures**. + +A fixture is a collection of data that Django knows how to import into a +database. For example, if your site has user accounts, you might set up a +fixture of fake user accounts in order to populate your database during tests. + +The most straightforward way of creating a fixture is to use the +:djadmin:`manage.py dumpdata <dumpdata>` command. This assumes you +already have some data in your database. See the :djadmin:`dumpdata +documentation<dumpdata>` for more details. + +.. note:: + If you've ever run :djadmin:`manage.py syncdb<syncdb>`, you've + already used a fixture without even knowing it! When you call + :djadmin:`syncdb` in the database for the first time, Django + installs a fixture called ``initial_data``. This gives you a way + of populating a new database with any initial data, such as a + default set of categories. + + Fixtures with other names can always be installed manually using + the :djadmin:`manage.py loaddata<loaddata>` command. + +Once you've created a fixture and placed it in a ``fixtures`` directory in one +of your :setting:`INSTALLED_APPS`, you can use it in your unit tests by +specifying a ``fixtures`` class attribute on your :class:`django.test.TestCase` +subclass:: + + from django.test import TestCase + from myapp.models import Animal + + class AnimalTestCase(TestCase): + fixtures = ['mammals.json', 'birds'] + + def setUp(self): + # Test definitions as before. + call_setup_methods() + + def testFluffyAnimals(self): + # A test that uses the fixtures. + call_some_test_code() + +Here's specifically what will happen: + + * At the start of each test case, before ``setUp()`` is run, Django will + flush the database, returning the database to the state it was in + directly after :djadmin:`syncdb` was called. + + * Then, all the named fixtures are installed. In this example, Django will + install any JSON fixture named ``mammals``, followed by any fixture named + ``birds``. See the :djadmin:`loaddata` documentation for more + details on defining and installing fixtures. + +This flush/load procedure is repeated for each test in the test case, so you +can be certain that the outcome of a test will not be affected by another test, +or by the order of test execution. + +URLconf configuration +~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.0 + +.. attribute:: TestCase.urls + +If your application provides views, you may want to include tests that use the +test client to exercise those views. However, an end user is free to deploy the +views in your application at any URL of their choosing. This means that your +tests can't rely upon the fact that your views will be available at a +particular URL. + +In order to provide a reliable URL space for your test, +``django.test.TestCase`` provides the ability to customize the URLconf +configuration for the duration of the execution of a test suite. If your +``TestCase`` instance defines an ``urls`` attribute, the ``TestCase`` will use +the value of that attribute as the ``ROOT_URLCONF`` for the duration of that +test. + +For example:: + + from django.test import TestCase + + class TestMyViews(TestCase): + urls = 'myapp.test_urls' + + def testIndexPageView(self): + # Here you'd test your view using ``Client``. + call_some_test_code() + +This test case will use the contents of ``myapp.test_urls`` as the +URLconf for the duration of the test case. + +.. _emptying-test-outbox: + +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 +is consumed by the call to ``flush`` that ensures that you have a +clean database at the start of each test run. If you have multiple +databases, multiple flushes are required (one for each database), +which can be a time consuming activity -- especially if your tests +don't need to test multi-database activity. + +As an optimization, Django only flushes the ``default`` database at +the start of each test run. If your setup contains multiple databases, +and you have a test that requires every database to be clean, you can +use the ``multi_db`` attribute on the test suite to request a full +flush. + +For example:: + + class TestMyViews(TestCase): + multi_db = True + + def testIndexPageView(self): + call_some_test_code() + +This test case will flush *all* the test databases before running +``testIndexPageView``. + +Emptying the test outbox +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.0 + +If you use Django's custom ``TestCase`` class, the test runner will clear the +contents of the test e-mail outbox at the start of each test case. + +For more detail on e-mail services during tests, see `E-mail services`_. + +Assertions +~~~~~~~~~~ + +.. versionadded:: 1.0 + +.. versionchanged:: 1.2 + Addded ``msg_prefix`` argument. + +As Python's normal ``unittest.TestCase`` class implements assertion methods +such as ``assertTrue`` and ``assertEquals``, Django's custom ``TestCase`` class +provides a number of custom assertion methods that are useful for testing Web +applications: + +The failure messages given by the assertion methods can be customized +with the ``msg_prefix`` argument. This string will be prefixed to any +failure message generated by the assertion. This allows you to provide +additional details that may help you to identify the location and +cause of an failure in your test suite. + +.. method:: TestCase.assertContains(response, text, count=None, status_code=200, msg_prefix='') + + Asserts that a ``Response`` instance produced the given ``status_code`` and + that ``text`` appears in the content of the response. If ``count`` is + provided, ``text`` must occur exactly ``count`` times in the response. + +.. method:: TestCase.assertNotContains(response, text, status_code=200, msg_prefix='') + + Asserts that a ``Response`` instance produced the given ``status_code`` and + that ``text`` does not appears in the content of the response. + +.. method:: TestCase.assertFormError(response, form, field, errors, msg_prefix='') + + Asserts that a field on a form raises the provided list of errors when + rendered on the form. + + ``form`` is the name the ``Form`` instance was given in the template + context. + + ``field`` is the name of the field on the form to check. If ``field`` + has a value of ``None``, non-field errors (errors you can access via + ``form.non_field_errors()``) will be checked. + + ``errors`` is an error string, or a list of error strings, that are + expected as a result of form validation. + +.. method:: TestCase.assertTemplateUsed(response, template_name, msg_prefix='') + + Asserts that the template with the given name was used in rendering the + response. + + The name is a string such as ``'admin/index.html'``. + +.. method:: TestCase.assertTemplateNotUsed(response, template_name, msg_prefix='') + + Asserts that the template with the given name was *not* used in rendering + the response. + +.. method:: TestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='') + + Asserts that the response return a ``status_code`` redirect status, it + redirected to ``expected_url`` (including any GET data), and the final + page was received with ``target_status_code``. + + .. versionadded:: 1.1 + + If your request used the ``follow`` argument, the ``expected_url`` and + ``target_status_code`` will be the url and status code for the final + point of the redirect chain. + +.. _topics-testing-email: + +E-mail services +--------------- + +.. versionadded:: 1.0 + +If any of your Django views send e-mail using :doc:`Django's e-mail +functionality </topics/email>`, you probably don't want to send e-mail each time +you run a test using that view. For this reason, Django's test runner +automatically redirects all Django-sent e-mail to a dummy outbox. This lets you +test every aspect of sending e-mail -- from the number of messages sent to the +contents of each message -- without actually sending the messages. + +The test runner accomplishes this by transparently replacing the normal +email backend with a testing backend. +(Don't worry -- this has no effect on any other e-mail senders outside of +Django, such as your machine's mail server, if you're running one.) + +.. currentmodule:: django.core.mail + +.. data:: django.core.mail.outbox + +During test running, each outgoing e-mail is saved in +``django.core.mail.outbox``. This is a simple list of all +:class:`~django.core.mail.EmailMessage` instances that have been sent. +The ``outbox`` attribute is a special attribute that is created *only* when +the ``locmem`` e-mail backend is used. It doesn't normally exist as part of the +:mod:`django.core.mail` module and you can't import it directly. The code +below shows how to access this attribute correctly. + +Here's an example test that examines ``django.core.mail.outbox`` for length +and contents:: + + from django.core import mail + from django.test import TestCase + + class EmailTest(TestCase): + def test_send_email(self): + # Send message. + mail.send_mail('Subject here', 'Here is the message.', + 'from@example.com', ['to@example.com'], + fail_silently=False) + + # Test that one message has been sent. + self.assertEquals(len(mail.outbox), 1) + + # Verify that the subject of the first message is correct. + self.assertEquals(mail.outbox[0].subject, 'Subject here') + +As noted :ref:`previously <emptying-test-outbox>`, the test outbox is emptied +at the start of every test in a Django ``TestCase``. To empty the outbox +manually, assign the empty list to ``mail.outbox``:: + + from django.core import mail + + # Empty the test outbox + mail.outbox = [] + +Using different testing frameworks +================================== + +Clearly, ``doctest`` and ``unittest`` are not the only Python testing +frameworks. While Django doesn't provide explicit support for alternative +frameworks, it does provide a way to invoke tests constructed for an +alternative framework as if they were normal Django tests. + +When you run ``./manage.py test``, Django looks at the :setting:`TEST_RUNNER` +setting to determine what to do. By default, :setting:`TEST_RUNNER` points to +``'django.test.simple.DjangoTestSuiteRunner'``. This class defines the default Django +testing behavior. This behavior involves: + + #. Performing global pre-test setup. + + #. Looking for unit tests and doctests in the ``models.py`` and + ``tests.py`` files in each installed application. + + #. Creating the test databases. + + #. Running ``syncdb`` to install models and initial data into the test + databases. + + #. Running the unit tests and doctests that are found. + + #. Destroying the test databases. + + #. Performing global post-test teardown. + +If you define your own test runner class and point :setting:`TEST_RUNNER` at +that class, Django will execute your test runner whenever you run +``./manage.py test``. In this way, it is possible to use any test framework +that can be executed from Python code, or to modify the Django test execution +process to satisfy whatever testing requirements you may have. + +.. _topics-testing-test_runner: + +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 +with a ``DjangoTestSuiteRunner`` class that defines the default Django +testing behavior. This class defines the ``run_tests()`` entry point, +plus a selection of other methods that are used to by ``run_tests()`` to +set up, execute and tear down the test suite. + +.. class:: DjangoTestSuiteRunner(verbosity=1, interactive=True, failfast=True, **kwargs) + + ``verbosity`` determines the amount of notification and debug information + that will be printed to the console; ``0`` is no output, ``1`` is normal + output, and ``2`` is verbose output. + + If ``interactive`` is ``True``, the test suite has permission to ask the + user for instructions when the test suite is executed. An example of this + behavior would be asking for permission to delete an existing test + database. If ``interactive`` is ``False``, the test suite must be able to + run without any manual intervention. + + If ``failfast`` is ``True``, the test suite will stop running after the + first test failure is detected. + + Django will, from time to time, extend the capabilities of + the test runner by adding new arguments. The ``**kwargs`` declaration + allows for this expansion. If you subclass ``DjangoTestSuiteRunner`` or + write your own test runner, ensure accept and handle the ``**kwargs`` + parameter. + +.. method:: DjangoTestSuiteRunner.run_tests(test_labels, extra_tests=None, **kwargs) + + Run the test suite. + + ``test_labels`` is a list of strings describing the tests to be run. A test + label can take one of three forms: + + * ``app.TestCase.test_method`` -- Run a single test method in a test + case. + * ``app.TestCase`` -- Run all the test methods in a test case. + * ``app`` -- Search for and run all tests in the named application. + + If ``test_labels`` has a value of ``None``, the test runner should run + search for tests in all the applications in :setting:`INSTALLED_APPS`. + + ``extra_tests`` is a list of extra ``TestCase`` instances to add to the + suite that is executed by the test runner. These extra tests are run + in addition to those discovered in the modules listed in ``test_labels``. + + This method should return the number of tests that failed. + +.. method:: DjangoTestSuiteRunner.setup_test_environment(**kwargs) + + Sets up the test environment ready for testing. + +.. method:: DjangoTestSuiteRunner.build_suite(test_labels, extra_tests=None, **kwargs) + + Constructs a test suite that matches the test labels provided. + + ``test_labels`` is a list of strings describing the tests to be run. A test + label can take one of three forms: + + * ``app.TestCase.test_method`` -- Run a single test method in a test + case. + * ``app.TestCase`` -- Run all the test methods in a test case. + * ``app`` -- Search for and run all tests in the named application. + + If ``test_labels`` has a value of ``None``, the test runner should run + search for tests in all the applications in :setting:`INSTALLED_APPS`. + + ``extra_tests`` is a list of extra ``TestCase`` instances to add to the + suite that is executed by the test runner. These extra tests are run + in addition to those discovered in the modules listed in ``test_labels``. + + Returns a ``TestSuite`` instance ready to be run. + +.. method:: DjangoTestSuiteRunner.setup_databases(**kwargs) + + Creates the test databases. + + Returns a data structure that provides enough detail to undo the changes + that have been made. This data will be provided to the ``teardown_databases()`` + function at the conclusion of testing. + +.. method:: DjangoTestSuiteRunner.run_suite(suite, **kwargs) + + Runs the test suite. + + Returns the result produced by the running the test suite. + +.. method:: DjangoTestSuiteRunner.teardown_databases(old_config, **kwargs) + + Destroys the test databases, restoring pre-test conditions. + + ``old_config`` is a data structure defining the changes in the + database configuration that need to be reversed. It is the return + value of the ``setup_databases()`` method. + +.. method:: DjangoTestSuiteRunner.teardown_test_environment(**kwargs) + + Restores the pre-test environment. + +.. method:: DjangoTestSuiteRunner.suite_result(suite, result, **kwargs) + + Computes and returns a return code based on a test suite, and the result + from that test suite. + + +Testing utilities +----------------- + +.. module:: django.test.utils + :synopsis: Helpers to write custom test runners. + +To assist in the creation of your own test runner, Django provides a number of +utility methods in the ``django.test.utils`` module. + +.. function:: setup_test_environment() + + Performs any global pre-test setup, such as the installing the + instrumentation of the template rendering system and setting up + the dummy ``SMTPConnection``. + +.. function:: teardown_test_environment() + + Performs any global post-test teardown, such as removing the black + magic hooks into the template system and restoring normal e-mail + services. + +The creation module of the database backend (``connection.creation``) +also provides some utilities that can be useful during testing. + +.. function:: create_test_db(verbosity=1, autoclobber=False) + + Creates a new test database and runs ``syncdb`` against it. + + ``verbosity`` has the same behavior as in ``run_tests()``. + + ``autoclobber`` describes the behavior that will occur if a + database with the same name as the test database is discovered: + + * If ``autoclobber`` is ``False``, the user will be asked to + approve destroying the existing database. ``sys.exit`` is + called if the user does not approve. + + * If autoclobber is ``True``, the database will be destroyed + without consulting the user. + + Returns the name of the test database that it created. + + ``create_test_db()`` has the side effect of modifying the value of + :setting:`NAME` in :setting:`DATABASES` to match the name of the test + database. + + .. versionchanged:: 1.0 + ``create_test_db()`` now returns the name of the test database. + +.. function:: destroy_test_db(old_database_name, verbosity=1) + + Destroys the database whose name is in stored in :setting:`NAME` in the + :setting:`DATABASES`, and sets :setting:`NAME` to use the + provided name. + + ``verbosity`` has the same behavior as in ``run_tests()``. |