mirror of
https://github.com/django/django.git
synced 2025-08-03 18:38:50 +00:00
Fixed #30573 -- Rephrased documentation to avoid words that minimise the involved difficulty.
This patch does not remove all occurrences of the words in question. Rather, I went through all of the occurrences of the words listed below, and judged if they a) suggested the reader had some kind of knowledge/experience, and b) if they added anything of value (including tone of voice, etc). I left most of the words alone. I looked at the following words: - simply/simple - easy/easier/easiest - obvious - just - merely - straightforward - ridiculous Thanks to Carlton Gibson for guidance on how to approach this issue, and to Tim Bell for providing the idea. But the enormous lion's share of thanks go to Adam Johnson for his patient and helpful review.
This commit is contained in:
parent
addabc492b
commit
4a954cfd11
149 changed files with 1101 additions and 1157 deletions
|
@ -82,8 +82,8 @@ backends that follow.
|
|||
authenticated user is needed. This effectively means that authentication
|
||||
sources are cached on a per-session basis, 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()``.
|
||||
you need to force users to re-authenticate using different methods. A
|
||||
simple way to do that is to execute ``Session.objects.all().delete()``.
|
||||
|
||||
Writing an authentication backend
|
||||
---------------------------------
|
||||
|
@ -98,7 +98,7 @@ database ID or whatever, but has to be the primary key of your user object --
|
|||
and returns a user object or ``None``.
|
||||
|
||||
The ``authenticate`` method takes a ``request`` argument and credentials as
|
||||
keyword arguments. Most of the time, it'll just look like this::
|
||||
keyword arguments. Most of the time, it'll look like this::
|
||||
|
||||
from django.contrib.auth.backends import BaseBackend
|
||||
|
||||
|
@ -197,7 +197,7 @@ exception in :meth:`~django.contrib.auth.models.User.has_perm()` or
|
|||
:meth:`~django.contrib.auth.models.User.has_module_perms()`, the authorization
|
||||
will immediately fail and Django won't check the backends that follow.
|
||||
|
||||
A backend could implement permissions for the magic admin fairly simply::
|
||||
A backend could implement permissions for the magic admin like this::
|
||||
|
||||
from django.contrib.auth.backends import BaseBackend
|
||||
|
||||
|
@ -729,7 +729,7 @@ Writing a manager for a custom user model
|
|||
You should also define a custom manager for your user model. If your user model
|
||||
defines ``username``, ``email``, ``is_staff``, ``is_active``, ``is_superuser``,
|
||||
``last_login``, and ``date_joined`` fields the same as Django's default user,
|
||||
you can just install Django's :class:`~django.contrib.auth.models.UserManager`;
|
||||
you can install Django's :class:`~django.contrib.auth.models.UserManager`;
|
||||
however, if your user model defines different fields, you'll need to define a
|
||||
custom manager that extends :class:`~django.contrib.auth.models.BaseUserManager`
|
||||
providing two additional methods:
|
||||
|
@ -793,10 +793,10 @@ Extending Django's default ``User``
|
|||
-----------------------------------
|
||||
|
||||
If you're entirely happy with Django's :class:`~django.contrib.auth.models.User`
|
||||
model and you just want to add some additional profile information, you could
|
||||
simply subclass :class:`django.contrib.auth.models.AbstractUser` and add your
|
||||
custom profile fields, although we'd recommend a separate model as described in
|
||||
the "Model design considerations" note of :ref:`specifying-custom-user-model`.
|
||||
model, but you want to add some additional profile information, you could
|
||||
subclass :class:`django.contrib.auth.models.AbstractUser` and add your custom
|
||||
profile fields, although we'd recommend a separate model as described in the
|
||||
"Model design considerations" note of :ref:`specifying-custom-user-model`.
|
||||
``AbstractUser`` provides the full implementation of the default
|
||||
:class:`~django.contrib.auth.models.User` as an :ref:`abstract model
|
||||
<abstract-base-classes>`.
|
||||
|
@ -835,8 +835,8 @@ to work with a custom user model:
|
|||
* :class:`~django.contrib.auth.forms.UserCreationForm`
|
||||
* :class:`~django.contrib.auth.forms.UserChangeForm`
|
||||
|
||||
If your custom user model is a simple subclass of ``AbstractUser``, then you
|
||||
can extend these forms in this manner::
|
||||
If your custom user model is a subclass of ``AbstractUser``, then you can
|
||||
extend these forms in this manner::
|
||||
|
||||
from django.contrib.auth.forms import UserCreationForm
|
||||
from myapp.models import CustomUser
|
||||
|
@ -1009,10 +1009,10 @@ A full example
|
|||
|
||||
Here is an example of an admin-compliant custom user app. This user model uses
|
||||
an email address as the username, and has a required date of birth; it
|
||||
provides no permission checking, beyond a simple ``admin`` flag on the user
|
||||
account. This model would be compatible with all the built-in auth forms and
|
||||
views, except for the user creation forms. This example illustrates how most of
|
||||
the components work together, but is not intended to be copied directly into
|
||||
provides no permission checking beyond an ``admin`` flag on the user account.
|
||||
This model would be compatible with all the built-in auth forms and views,
|
||||
except for the user creation forms. This example illustrates how most of the
|
||||
components work together, but is not intended to be copied directly into
|
||||
projects for production use.
|
||||
|
||||
This code would all live in a ``models.py`` file for a custom
|
||||
|
|
|
@ -150,7 +150,7 @@ Authenticating users
|
|||
Permissions and Authorization
|
||||
=============================
|
||||
|
||||
Django comes with a simple permissions system. It provides a way to assign
|
||||
Django comes with a built-in 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
|
||||
|
@ -473,7 +473,7 @@ Limiting access to logged-in users
|
|||
The raw way
|
||||
~~~~~~~~~~~
|
||||
|
||||
The simple, raw way to limit access to pages is to check
|
||||
The raw way to limit access to pages is to check
|
||||
:attr:`request.user.is_authenticated
|
||||
<django.contrib.auth.models.User.is_authenticated>` and either redirect to a
|
||||
login page::
|
||||
|
@ -615,10 +615,9 @@ Limiting access to logged-in users that pass a test
|
|||
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 has an email in the desired domain and if not,
|
||||
redirects to the login page::
|
||||
You can 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 has an
|
||||
email in the desired domain and if not, redirects to the login page::
|
||||
|
||||
from django.shortcuts import redirect
|
||||
|
||||
|
@ -1015,8 +1014,8 @@ implementation details see :ref:`using-the-views`.
|
|||
* ``redirect_field_name``: The name of a ``GET`` field containing the
|
||||
URL to redirect to after login. Defaults to ``next``.
|
||||
|
||||
* ``authentication_form``: A callable (typically just a form class) to
|
||||
use for authentication. Defaults to
|
||||
* ``authentication_form``: A callable (typically a form class) to use for
|
||||
authentication. Defaults to
|
||||
:class:`~django.contrib.auth.forms.AuthenticationForm`.
|
||||
|
||||
* ``extra_context``: A dictionary of context data that will be added to the
|
||||
|
|
|
@ -423,8 +423,8 @@ Password validation
|
|||
|
||||
Users often choose poor passwords. To help mitigate this problem, Django
|
||||
offers pluggable password validation. You can configure multiple password
|
||||
validators at the same time. A few validators are included in Django, but it's
|
||||
simple to write your own as well.
|
||||
validators at the same time. A few validators are included in Django, but you
|
||||
can write your own as well.
|
||||
|
||||
Each password validator must provide a help text to explain the requirements to
|
||||
the user, validate a given password and return an error message if it does not
|
||||
|
@ -434,7 +434,7 @@ Validators can also have optional settings to fine tune their behavior.
|
|||
Validation is controlled by the :setting:`AUTH_PASSWORD_VALIDATORS` setting.
|
||||
The default for the setting is an empty list, which means no validators are
|
||||
applied. In new projects created with the default :djadmin:`startproject`
|
||||
template, a simple set of validators is enabled.
|
||||
template, a set of validators is enabled by default.
|
||||
|
||||
By default, validators are used in the forms to reset or change passwords and
|
||||
in the :djadmin:`createsuperuser` and :djadmin:`changepassword` management
|
||||
|
@ -479,10 +479,9 @@ This example enables all four included validators:
|
|||
|
||||
* ``UserAttributeSimilarityValidator``, which checks the similarity between
|
||||
the password and a set of attributes of the user.
|
||||
* ``MinimumLengthValidator``, which simply checks whether the password meets a
|
||||
minimum length. This validator is configured with a custom option: it now
|
||||
requires the minimum length to be nine characters, instead of the default
|
||||
eight.
|
||||
* ``MinimumLengthValidator``, which checks whether the password meets a minimum
|
||||
length. This validator is configured with a custom option: it now requires
|
||||
the minimum length to be nine characters, instead of the default eight.
|
||||
* ``CommonPasswordValidator``, which checks whether the password occurs in a
|
||||
list of common passwords. By default, it compares to an included list of
|
||||
20,000 common passwords.
|
||||
|
@ -490,8 +489,8 @@ This example enables all four included validators:
|
|||
entirely numeric.
|
||||
|
||||
For ``UserAttributeSimilarityValidator`` and ``CommonPasswordValidator``,
|
||||
we're simply using the default settings in this example.
|
||||
``NumericPasswordValidator`` has no settings.
|
||||
we're using the default settings in this example. ``NumericPasswordValidator``
|
||||
has no settings.
|
||||
|
||||
The help texts and any errors from password validators are always returned in
|
||||
the order they are listed in :setting:`AUTH_PASSWORD_VALIDATORS`.
|
||||
|
@ -601,15 +600,15 @@ Writing your own validator
|
|||
--------------------------
|
||||
|
||||
If Django's built-in validators are not sufficient, you can write your own
|
||||
password validators. Validators are fairly simple classes. They must implement
|
||||
two methods:
|
||||
password validators. Validators have a fairly small interface. They must
|
||||
implement two methods:
|
||||
|
||||
* ``validate(self, password, user=None)``: validate a password. Return
|
||||
``None`` if the password is valid, or raise a
|
||||
:exc:`~django.core.exceptions.ValidationError` with an error message if the
|
||||
password is not valid. You must be able to deal with ``user`` being
|
||||
``None`` - if that means your validator can't run, simply return ``None``
|
||||
for no error.
|
||||
``None`` - if that means your validator can't run, return ``None`` for no
|
||||
error.
|
||||
* ``get_help_text()``: provide a help text to explain the requirements to
|
||||
the user.
|
||||
|
||||
|
|
|
@ -10,9 +10,9 @@ 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.
|
||||
applications aren't ``washingtonpost.com`` or ``slashdot.org``; they're 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.
|
||||
|
||||
|
@ -366,7 +366,7 @@ as reference implementations. You'll find the code in the
|
|||
|
||||
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.
|
||||
been well-tested and are well-documented.
|
||||
|
||||
.. _cache_arguments:
|
||||
|
||||
|
@ -556,8 +556,7 @@ 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::
|
||||
decorator that will automatically cache the view's response for you::
|
||||
|
||||
from django.views.decorators.cache import cache_page
|
||||
|
||||
|
@ -618,8 +617,8 @@ 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::
|
||||
You can do so by wrapping the view function with ``cache_page`` when you refer
|
||||
to it in the URLconf. Here's the old URLconf from earlier::
|
||||
|
||||
urlpatterns = [
|
||||
path('foo/<int:code>/', my_view),
|
||||
|
@ -697,7 +696,7 @@ equivalent:
|
|||
{% 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.
|
||||
timeout in a variable, in one place, and reuse that value.
|
||||
|
||||
By default, the cache tag will try to use the cache called "template_fragments".
|
||||
If no such cache exists, it will fall back to using the default cache. You may
|
||||
|
@ -743,11 +742,11 @@ 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
|
||||
For cases like this, Django exposes a 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.)
|
||||
|
||||
Accessing the cache
|
||||
|
@ -840,7 +839,7 @@ check the return value. It will return ``True`` if the value was stored,
|
|||
|
||||
If you want to get a key's value or set a value if the key isn't in the cache,
|
||||
there is the ``get_or_set()`` method. It takes the same parameters as ``get()``
|
||||
but the default is set as the new cache value for that key, rather than simply
|
||||
but the default is set as the new cache value for that key, rather than
|
||||
returned::
|
||||
|
||||
>>> cache.get('my_new_key') # returns None
|
||||
|
@ -881,8 +880,8 @@ failed to be inserted.
|
|||
|
||||
.. method:: cache.delete(key, version=None)
|
||||
|
||||
You can delete keys explicitly with ``delete()``. This is an easy way of
|
||||
clearing the cache for a particular object::
|
||||
You can delete keys explicitly with ``delete()`` to clear the cache for a
|
||||
particular object::
|
||||
|
||||
>>> cache.delete('a')
|
||||
|
||||
|
@ -1111,11 +1110,11 @@ 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 email 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
|
||||
their user-specific inbox page cached for subsequent visitors to the site.
|
||||
That's not cool.
|
||||
For example, if you operate a Web email system, then the contents of the
|
||||
"inbox" page 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 their
|
||||
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 downstream caches to differ their cache contents depending on
|
||||
|
|
|
@ -29,8 +29,8 @@ Django ships with generic views to do the following:
|
|||
* 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.
|
||||
Taken together, these views provide interfaces to perform the most common tasks
|
||||
developers encounter.
|
||||
|
||||
|
||||
Extending generic views
|
||||
|
@ -43,10 +43,10 @@ Django developers is how to make generic views handle a wider array of
|
|||
situations.
|
||||
|
||||
This is one of the reasons generic views were redesigned for the 1.3 release -
|
||||
previously, they were just view functions with a bewildering array of options;
|
||||
now, rather than passing in a large amount of configuration in the URLconf,
|
||||
the recommended way to extend generic views is to subclass them, and override
|
||||
their attributes or methods.
|
||||
previously, they were view functions with a bewildering array of options; now,
|
||||
rather than passing in a large amount of configuration in the URLconf, the
|
||||
recommended way to extend generic views is to subclass them, and override their
|
||||
attributes or methods.
|
||||
|
||||
That said, generic views will have a limit. If you find you're struggling to
|
||||
implement your view as a subclass of a generic view, then you may find it more
|
||||
|
@ -63,8 +63,7 @@ Generic views of objects
|
|||
:class:`~django.views.generic.base.TemplateView` certainly is useful, but
|
||||
Django's generic views really shine when it comes to presenting views of your
|
||||
database content. Because it's such a common task, Django comes with a handful
|
||||
of built-in generic views that make generating list and detail views of objects
|
||||
incredibly easy.
|
||||
of built-in generic views to help generate list and detail views of objects.
|
||||
|
||||
Let's start by looking at some examples of showing a list of objects or an
|
||||
individual object.
|
||||
|
@ -130,7 +129,7 @@ however. We could explicitly tell the view which template to use by adding a
|
|||
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.
|
||||
bit is the lowercased version of the model's name.
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -139,8 +138,8 @@ bit is just the lowercased version of the model's name.
|
|||
be: /path/to/project/books/templates/books/publisher_list.html
|
||||
|
||||
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:
|
||||
``object_list`` that contains all the publisher objects. A template might look
|
||||
like the this:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
|
@ -197,17 +196,16 @@ coworkers who design templates will thank you.
|
|||
Adding extra context
|
||||
--------------------
|
||||
|
||||
Often you simply need to present some extra information beyond that
|
||||
provided by the generic view. For example, think of showing a list of
|
||||
all the books on each publisher detail page. The
|
||||
:class:`~django.views.generic.detail.DetailView` generic view provides
|
||||
the publisher to the context, but how do we get additional information
|
||||
in that template?
|
||||
Often you need to present some extra information beyond that provided by the
|
||||
generic view. For example, think of showing a list of all the books on each
|
||||
publisher detail page. The :class:`~django.views.generic.detail.DetailView`
|
||||
generic view provides the publisher to the context, but how do we get
|
||||
additional information in that template?
|
||||
|
||||
The answer is to subclass :class:`~django.views.generic.detail.DetailView`
|
||||
and provide your own implementation of the ``get_context_data`` method.
|
||||
The default implementation simply adds the object being displayed to the
|
||||
template, but you can override it to send more::
|
||||
The default implementation adds the object being displayed to the template, but
|
||||
you can override it to send more::
|
||||
|
||||
from django.views.generic import DetailView
|
||||
from books.models import Book, Publisher
|
||||
|
@ -261,16 +259,16 @@ specify the list of objects using the ``queryset`` argument::
|
|||
context_object_name = 'publisher'
|
||||
queryset = Publisher.objects.all()
|
||||
|
||||
Specifying ``model = Publisher`` is really just shorthand for saying
|
||||
``queryset = Publisher.objects.all()``. However, by using ``queryset``
|
||||
to define a filtered list of objects you can be more specific about the
|
||||
objects that will be visible in the view (see :doc:`/topics/db/queries`
|
||||
for more information about :class:`~django.db.models.query.QuerySet` objects,
|
||||
and see the :doc:`class-based views reference </ref/class-based-views/index>`
|
||||
for the complete details).
|
||||
Specifying ``model = Publisher`` is shorthand for saying ``queryset =
|
||||
Publisher.objects.all()``. However, by using ``queryset`` to define a filtered
|
||||
list of objects you can be more specific about the objects that will be visible
|
||||
in the view (see :doc:`/topics/db/queries` for more information about
|
||||
:class:`~django.db.models.query.QuerySet` objects, and see the
|
||||
:doc:`class-based views reference </ref/class-based-views/index>` for the
|
||||
complete details).
|
||||
|
||||
To pick a simple example, we might want to order a list of books by
|
||||
publication date, with the most recent first::
|
||||
To pick an example, we might want to order a list of books by publication date,
|
||||
with the most recent first::
|
||||
|
||||
from django.views.generic import ListView
|
||||
from books.models import Book
|
||||
|
@ -279,7 +277,7 @@ publication date, with the most recent first::
|
|||
queryset = Book.objects.order_by('-publication_date')
|
||||
context_object_name = 'book_list'
|
||||
|
||||
That's a pretty simple example, but it illustrates the idea nicely. Of course,
|
||||
That's a pretty minimal 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::
|
||||
|
@ -321,8 +319,8 @@ publisher?
|
|||
|
||||
Handily, the ``ListView`` has a
|
||||
:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset` method we
|
||||
can override. Previously, it has just been returning the value of the
|
||||
``queryset`` attribute, but now we can add more logic.
|
||||
can override. By default, it returns the value of the ``queryset`` attribute,
|
||||
but we can use it to add more logic.
|
||||
|
||||
The key part to making this work is that when class-based views are called,
|
||||
various useful things are stored on ``self``; as well as the request
|
||||
|
@ -354,9 +352,10 @@ Next, we'll write the ``PublisherBookList`` view itself::
|
|||
self.publisher = get_object_or_404(Publisher, name=self.kwargs['publisher'])
|
||||
return Book.objects.filter(publisher=self.publisher)
|
||||
|
||||
As you can see, it's quite easy to add more logic to the queryset selection;
|
||||
if we wanted, we could use ``self.request.user`` to filter using the current
|
||||
user, or other more complex logic.
|
||||
Using ``get_queryset`` to add logic to the queryset selection is as convenient
|
||||
as it is powerful. For instance, if we wanted, we could use
|
||||
``self.request.user`` to filter using the current user, or other more complex
|
||||
logic.
|
||||
|
||||
We can also add the publisher into the context at the same time, so we can
|
||||
use it in the template::
|
||||
|
@ -407,7 +406,7 @@ custom view::
|
|||
]
|
||||
|
||||
Then we'd write our new view -- ``get_object`` is the method that retrieves the
|
||||
object -- so we simply override it and wrap the call::
|
||||
object -- so we override it and wrap the call::
|
||||
|
||||
from django.utils import timezone
|
||||
from django.views.generic import DetailView
|
||||
|
|
|
@ -16,7 +16,7 @@ processing.
|
|||
Basic forms
|
||||
===========
|
||||
|
||||
Given a simple contact form:
|
||||
Given a contact form:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: forms.py
|
||||
|
@ -85,7 +85,7 @@ You don't even need to provide a ``success_url`` for
|
|||
:meth:`~django.db.models.Model.get_absolute_url()` on the model object if available.
|
||||
|
||||
If you want to use a custom :class:`~django.forms.ModelForm` (for instance to
|
||||
add extra validation) simply set
|
||||
add extra validation), set
|
||||
:attr:`~django.views.generic.edit.FormMixin.form_class` on your view.
|
||||
|
||||
.. note::
|
||||
|
@ -132,8 +132,8 @@ here; we don't have to write any logic ourselves:
|
|||
success_url = reverse_lazy('author-list')
|
||||
|
||||
.. note::
|
||||
We have to use :func:`~django.urls.reverse_lazy` here, not just
|
||||
``reverse()`` as the urls are not loaded when the file is imported.
|
||||
We have to use :func:`~django.urls.reverse_lazy` instead of
|
||||
``reverse()``, as the urls are not loaded when the file is imported.
|
||||
|
||||
The ``fields`` attribute works the same way as the ``fields`` attribute on the
|
||||
inner ``Meta`` class on :class:`~django.forms.ModelForm`. Unless you define the
|
||||
|
@ -225,7 +225,7 @@ handle unauthorized users in :meth:`~.ModelFormMixin.form_valid()`.
|
|||
AJAX example
|
||||
============
|
||||
|
||||
Here is a simple example showing how you might go about implementing a form that
|
||||
Here is an example showing how you might go about implementing a form that
|
||||
works for AJAX requests as well as 'normal' form POSTs::
|
||||
|
||||
from django.http import JsonResponse
|
||||
|
|
|
@ -6,10 +6,10 @@ A view is a callable which takes a request and returns a
|
|||
response. This can be more than just a function, and Django provides
|
||||
an example of some classes which can be used as views. These allow you
|
||||
to structure your views and reuse code by harnessing inheritance and
|
||||
mixins. There are also some generic views for simple tasks which we'll
|
||||
get to later, but you may want to design your own structure of
|
||||
reusable views which suits your use case. For full details, see the
|
||||
:doc:`class-based views reference documentation</ref/class-based-views/index>`.
|
||||
mixins. There are also some generic views for tasks which we'll get to later,
|
||||
but you may want to design your own structure of reusable views which suits
|
||||
your use case. For full details, see the :doc:`class-based views reference
|
||||
documentation</ref/class-based-views/index>`.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
@ -25,18 +25,18 @@ Basic examples
|
|||
Django provides base view classes which will suit a wide range of applications.
|
||||
All views inherit from the :class:`~django.views.generic.base.View` class, which
|
||||
handles linking the view in to the URLs, HTTP method dispatching and other
|
||||
simple features. :class:`~django.views.generic.base.RedirectView` is for a
|
||||
simple HTTP redirect, and :class:`~django.views.generic.base.TemplateView`
|
||||
extends the base class to make it also render a template.
|
||||
common features. :class:`~django.views.generic.base.RedirectView` provides a
|
||||
HTTP redirect, and :class:`~django.views.generic.base.TemplateView` extends the
|
||||
base class to make it also render a template.
|
||||
|
||||
|
||||
Simple usage in your URLconf
|
||||
============================
|
||||
Usage in your URLconf
|
||||
=====================
|
||||
|
||||
The simplest way to use generic views is to create them directly in your
|
||||
URLconf. If you're only changing a few simple attributes on a class-based view,
|
||||
you can simply pass them into the
|
||||
:meth:`~django.views.generic.base.View.as_view` method call itself::
|
||||
The most direct way to use generic views is to create them directly in your
|
||||
URLconf. If you're only changing a few attributes on a class-based view, you
|
||||
can pass them into the :meth:`~django.views.generic.base.View.as_view` method
|
||||
call itself::
|
||||
|
||||
from django.urls import path
|
||||
from django.views.generic import TemplateView
|
||||
|
@ -59,8 +59,8 @@ existing view and override attributes (such as the ``template_name``) or
|
|||
methods (such as ``get_context_data``) in your subclass to provide new values
|
||||
or methods. Consider, for example, a view that just displays one template,
|
||||
``about.html``. Django has a generic view to do this -
|
||||
:class:`~django.views.generic.base.TemplateView` - so we can just subclass it,
|
||||
and override the template name::
|
||||
:class:`~django.views.generic.base.TemplateView` - so we can subclass it, and
|
||||
override the template name::
|
||||
|
||||
# some_app/views.py
|
||||
from django.views.generic import TemplateView
|
||||
|
@ -68,11 +68,10 @@ and override the template name::
|
|||
class AboutView(TemplateView):
|
||||
template_name = "about.html"
|
||||
|
||||
Then we just need to add this new view into our URLconf.
|
||||
:class:`~django.views.generic.base.TemplateView` is a class, not a function,
|
||||
so we point the URL to the :meth:`~django.views.generic.base.View.as_view`
|
||||
class method instead, which provides a function-like entry to class-based
|
||||
views::
|
||||
Then we need to add this new view into our URLconf.
|
||||
:class:`~django.views.generic.base.TemplateView` is a class, not a function, so
|
||||
we point the URL to the :meth:`~django.views.generic.base.View.as_view` class
|
||||
method instead, which provides a function-like entry to class-based views::
|
||||
|
||||
# urls.py
|
||||
from django.urls import path
|
||||
|
@ -123,9 +122,8 @@ And the view::
|
|||
response['Last-Modified'] = last_book.publication_date.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||
return response
|
||||
|
||||
If the view is accessed from a ``GET`` request, a plain-and-simple object
|
||||
list is returned in the response (using ``book_list.html`` template). But if
|
||||
the client issues a ``HEAD`` request, the response has an empty body and
|
||||
the ``Last-Modified`` header indicates when the most recent book was published.
|
||||
Based on this information, the client may or may not download the full object
|
||||
list.
|
||||
If the view is accessed from a ``GET`` request, an object list is returned in
|
||||
the response (using the ``book_list.html`` template). But if the client issues
|
||||
a ``HEAD`` request, the response has an empty body and the ``Last-Modified``
|
||||
header indicates when the most recent book was published. Based on this
|
||||
information, the client may or may not download the full object list.
|
||||
|
|
|
@ -25,7 +25,7 @@ these patterns and ease view development for the common cases.
|
|||
|
||||
The problem with function-based generic views is that while they covered the
|
||||
simple cases well, there was no way to extend or customize them beyond some
|
||||
simple configuration options, limiting their usefulness in many real-world
|
||||
configuration options, limiting their usefulness in many real-world
|
||||
applications.
|
||||
|
||||
Class-based generic views were created with the same objective as
|
||||
|
@ -35,9 +35,9 @@ results in class-based generic views being more extensible and flexible than
|
|||
their function-based counterparts.
|
||||
|
||||
If you have tried function based generic views in the past and found them
|
||||
lacking, you should not think of class-based generic views as simply a
|
||||
class-based equivalent, but rather as a fresh approach to solving the original
|
||||
problems that generic views were meant to solve.
|
||||
lacking, you should not think of class-based generic views as a class-based
|
||||
equivalent, but rather as a fresh approach to solving the original problems
|
||||
that generic views were meant to solve.
|
||||
|
||||
The toolkit of base classes and mixins that Django uses to build class-based
|
||||
generic views are built for maximum flexibility, and as such have many hooks in
|
||||
|
@ -45,11 +45,11 @@ the form of default method implementations and attributes that you are unlikely
|
|||
to be concerned with in the simplest use cases. For example, instead of
|
||||
limiting you to a class-based attribute for ``form_class``, the implementation
|
||||
uses a ``get_form`` method, which calls a ``get_form_class`` method, which in
|
||||
its default implementation just returns the ``form_class`` attribute of the
|
||||
class. This gives you several options for specifying what form to use, from a
|
||||
simple attribute, to a fully dynamic, callable hook. These options seem to add
|
||||
hollow complexity for simple situations, but without them, more advanced
|
||||
designs would be limited.
|
||||
its default implementation returns the ``form_class`` attribute of the class.
|
||||
This gives you several options for specifying what form to use, from an
|
||||
attribute, to a fully dynamic, callable hook. These options seem to add hollow
|
||||
complexity for simple situations, but without them, more advanced designs would
|
||||
be limited.
|
||||
|
||||
Using class-based views
|
||||
=======================
|
||||
|
@ -221,7 +221,7 @@ A similar class-based view might look like::
|
|||
|
||||
return render(request, self.template_name, {'form': form})
|
||||
|
||||
This is a very simple case, but you can see that you would then have the option
|
||||
This is a minimal case, but you can see that you would then have the option
|
||||
of customizing this view by overriding any of the class attributes, e.g.
|
||||
``form_class``, via URLconf configuration, or subclassing and overriding one or
|
||||
more of the methods (or both!).
|
||||
|
@ -236,9 +236,9 @@ differently depending on if you're using ``as_view()`` or creating a subclass.
|
|||
Decorating in URLconf
|
||||
---------------------
|
||||
|
||||
The simplest way of decorating class-based views is to decorate the
|
||||
result of the :meth:`~django.views.generic.base.View.as_view` method.
|
||||
The easiest place to do this is in the URLconf where you deploy your view::
|
||||
You can adjust class-based views by decorating the result of the
|
||||
:meth:`~django.views.generic.base.View.as_view` method. The easiest place to do
|
||||
this is in the URLconf where you deploy your view::
|
||||
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
from django.views.generic import TemplateView
|
||||
|
@ -263,11 +263,11 @@ To decorate every instance of a class-based view, you need to decorate
|
|||
the class definition itself. To do this you apply the decorator to the
|
||||
:meth:`~django.views.generic.base.View.dispatch` method of the class.
|
||||
|
||||
A method on a class isn't quite the same as a standalone function, so
|
||||
you can't just apply a function decorator to the method -- you need to
|
||||
transform it into a method decorator first. The ``method_decorator``
|
||||
decorator transforms a function decorator into a method decorator so
|
||||
that it can be used on an instance method. For example::
|
||||
A method on a class isn't quite the same as a standalone function, so you can't
|
||||
just apply a function decorator to the method -- you need to transform it into
|
||||
a method decorator first. The ``method_decorator`` decorator transforms a
|
||||
function decorator into a method decorator so that it can be used on an
|
||||
instance method. For example::
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.utils.decorators import method_decorator
|
||||
|
@ -306,9 +306,9 @@ The decorators will process a request in the order they are passed to the
|
|||
decorator. In the example, ``never_cache()`` will process the request before
|
||||
``login_required()``.
|
||||
|
||||
In this example, every instance of ``ProtectedView`` will have login protection.
|
||||
These examples use ``login_required``, however, the same behavior can be
|
||||
obtained more simply using
|
||||
In this example, every instance of ``ProtectedView`` will have login
|
||||
protection. These examples use ``login_required``, however, the same behavior
|
||||
can be obtained by using
|
||||
:class:`~django.contrib.auth.mixins.LoginRequiredMixin`.
|
||||
|
||||
.. note::
|
||||
|
|
|
@ -46,7 +46,7 @@ interface to working with templates in class-based views.
|
|||
|
||||
``render_to_response()`` itself calls
|
||||
:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`,
|
||||
which by default will just look up
|
||||
which by default will look up
|
||||
:attr:`~django.views.generic.base.TemplateResponseMixin.template_name` on
|
||||
the class-based view; two other mixins
|
||||
(:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`
|
||||
|
@ -61,8 +61,8 @@ interface to working with templates in class-based views.
|
|||
:meth:`~django.views.generic.base.ContextMixin.get_context_data()` passing
|
||||
any data they want to ensure is in there as keyword arguments.
|
||||
``get_context_data()`` returns a dictionary; in ``ContextMixin`` it
|
||||
simply returns its keyword arguments, but it is common to override this to
|
||||
add more members to the dictionary. You can also use the
|
||||
returns its keyword arguments, but it is common to override this to add
|
||||
more members to the dictionary. You can also use the
|
||||
:attr:`~django.views.generic.base.ContextMixin.extra_context` attribute.
|
||||
|
||||
Building up Django's generic class-based views
|
||||
|
@ -142,7 +142,7 @@ and
|
|||
:meth:`~django.views.generic.list.MultipleObjectMixin.paginate_queryset`. Unlike
|
||||
with :class:`~django.views.generic.detail.SingleObjectMixin`, there's no need
|
||||
to key off parts of the URL to figure out the queryset to work with, so the
|
||||
default just uses the
|
||||
default uses the
|
||||
:attr:`~django.views.generic.list.MultipleObjectMixin.queryset` or
|
||||
:attr:`~django.views.generic.list.MultipleObjectMixin.model` attribute
|
||||
on the view class. A common reason to override
|
||||
|
@ -212,11 +212,10 @@ the box.
|
|||
Using ``SingleObjectMixin`` with View
|
||||
-------------------------------------
|
||||
|
||||
If we want to write a simple class-based view that responds only to
|
||||
``POST``, we'll subclass :class:`~django.views.generic.base.View` and
|
||||
write a ``post()`` method in the subclass. However if we want our
|
||||
processing to work on a particular object, identified from the URL,
|
||||
we'll want the functionality provided by
|
||||
If we want to write a class-based view that responds only to ``POST``, we'll
|
||||
subclass :class:`~django.views.generic.base.View` and write a ``post()`` method
|
||||
in the subclass. However if we want our processing to work on a particular
|
||||
object, identified from the URL, we'll want the functionality provided by
|
||||
:class:`~django.views.generic.detail.SingleObjectMixin`.
|
||||
|
||||
We'll demonstrate this with the ``Author`` model we used in the
|
||||
|
@ -249,9 +248,8 @@ In practice you'd probably want to record the interest in a key-value
|
|||
store rather than in a relational database, so we've left that bit
|
||||
out. The only bit of the view that needs to worry about using
|
||||
:class:`~django.views.generic.detail.SingleObjectMixin` is where we want to
|
||||
look up the author we're interested in, which it just does with a simple call
|
||||
to ``self.get_object()``. Everything else is taken care of for us by the
|
||||
mixin.
|
||||
look up the author we're interested in, which it does with a call to
|
||||
``self.get_object()``. Everything else is taken care of for us by the mixin.
|
||||
|
||||
We can hook this into our URLs easily enough:
|
||||
|
||||
|
@ -288,8 +286,8 @@ object. In order to do this, we need to have two different querysets:
|
|||
|
||||
``Book`` queryset for use by :class:`~django.views.generic.list.ListView`
|
||||
Since we have access to the ``Publisher`` whose books we want to list, we
|
||||
simply override ``get_queryset()`` and use the ``Publisher``’s
|
||||
:ref:`reverse foreign key manager<backwards-related-objects>`.
|
||||
override ``get_queryset()`` and use the ``Publisher``’s :ref:`reverse
|
||||
foreign key manager<backwards-related-objects>`.
|
||||
|
||||
``Publisher`` queryset for use in :meth:`~django.views.generic.detail.SingleObjectMixin.get_object()`
|
||||
We'll rely on the default implementation of ``get_object()`` to fetch the
|
||||
|
@ -476,24 +474,23 @@ Our new ``AuthorDetail`` looks like this::
|
|||
# passed in form.cleaned_data['message']
|
||||
return super().form_valid(form)
|
||||
|
||||
``get_success_url()`` is just providing somewhere to redirect to,
|
||||
``get_success_url()`` is provides somewhere to redirect to,
|
||||
which gets used in the default implementation of
|
||||
``form_valid()``. We have to provide our own ``post()`` as noted earlier.
|
||||
|
||||
A better solution
|
||||
-----------------
|
||||
|
||||
It should be obvious that the number of subtle interactions between
|
||||
The number of subtle interactions between
|
||||
:class:`~django.views.generic.edit.FormMixin` and :class:`DetailView` is
|
||||
already testing our ability to manage things. It's unlikely you'd want to
|
||||
write this kind of class yourself.
|
||||
|
||||
In this case, it would be fairly easy to just write the ``post()``
|
||||
method yourself, keeping :class:`DetailView` as the only generic
|
||||
functionality, although writing :class:`~django.forms.Form` handling code
|
||||
involves a lot of duplication.
|
||||
In this case, you could write the ``post()`` method yourself, keeping
|
||||
:class:`DetailView` as the only generic functionality, although writing
|
||||
:class:`~django.forms.Form` handling code involves a lot of duplication.
|
||||
|
||||
Alternatively, it would still be easier than the above approach to
|
||||
Alternatively, it would still be less work than the above approach to
|
||||
have a separate view for processing the form, which could use
|
||||
:class:`~django.views.generic.edit.FormView` distinct from
|
||||
:class:`DetailView` without concerns.
|
||||
|
@ -529,11 +526,11 @@ write our own ``get_context_data()`` to make the
|
|||
context['form'] = AuthorInterestForm()
|
||||
return context
|
||||
|
||||
Then the ``AuthorInterest`` is a simple :class:`FormView`, but we
|
||||
have to bring in :class:`~django.views.generic.detail.SingleObjectMixin` so we
|
||||
can find the author we're talking about, and we have to remember to set
|
||||
``template_name`` to ensure that form errors will render the same
|
||||
template as ``AuthorDisplay`` is using on ``GET``::
|
||||
Then the ``AuthorInterest`` is a :class:`FormView`, but we have to bring in
|
||||
:class:`~django.views.generic.detail.SingleObjectMixin` so we can find the
|
||||
author we're talking about, and we have to remember to set ``template_name`` to
|
||||
ensure that form errors will render the same template as ``AuthorDisplay`` is
|
||||
using on ``GET``::
|
||||
|
||||
from django.http import HttpResponseForbidden
|
||||
from django.urls import reverse
|
||||
|
@ -593,7 +590,7 @@ rendered HTML.
|
|||
We can create a mixin class to use in all of our views, handling the
|
||||
conversion to JSON once.
|
||||
|
||||
For example, a simple JSON mixin might look something like this::
|
||||
For example, a JSON mixin might look something like this::
|
||||
|
||||
from django.http import JsonResponse
|
||||
|
||||
|
@ -628,8 +625,8 @@ For example, a simple JSON mixin might look something like this::
|
|||
|
||||
This mixin provides a ``render_to_json_response()`` method with the same signature
|
||||
as :func:`~django.views.generic.base.TemplateResponseMixin.render_to_response()`.
|
||||
To use it, we simply need to mix it into a ``TemplateView`` for example,
|
||||
and override ``render_to_response()`` to call ``render_to_json_response()`` instead::
|
||||
To use it, we need to mix it into a ``TemplateView`` for example, and override
|
||||
``render_to_response()`` to call ``render_to_json_response()`` instead::
|
||||
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
|
@ -657,8 +654,8 @@ same behavior -- except for the format of the response.
|
|||
If you want to be really adventurous, you could even mix a
|
||||
:class:`~django.views.generic.detail.DetailView` subclass that is able
|
||||
to return *both* HTML and JSON content, depending on some property of
|
||||
the HTTP request, such as a query argument or a HTTP header. Just mix
|
||||
in both the ``JSONResponseMixin`` and a
|
||||
the HTTP request, such as a query argument or a HTTP header. Mix in both the
|
||||
``JSONResponseMixin`` and a
|
||||
:class:`~django.views.generic.detail.SingleObjectTemplateResponseMixin`,
|
||||
and override the implementation of
|
||||
:func:`~django.views.generic.base.TemplateResponseMixin.render_to_response()`
|
||||
|
|
|
@ -71,7 +71,7 @@ if they are not already set by the view and if the request's method is safe
|
|||
(``GET`` or ``HEAD``).
|
||||
|
||||
Using this feature usefully is probably best explained with an example.
|
||||
Suppose you have this pair of models, representing a simple blog system::
|
||||
Suppose you have this pair of models, representing a small blog system::
|
||||
|
||||
import datetime
|
||||
from django.db import models
|
||||
|
@ -205,10 +205,9 @@ every time.
|
|||
Comparison with middleware conditional processing
|
||||
=================================================
|
||||
|
||||
Django provides simple and straightforward conditional ``GET`` handling via
|
||||
:class:`django.middleware.http.ConditionalGetMiddleware`. While being easy to
|
||||
use and suitable for many situations, the middleware has limitations for
|
||||
advanced usage:
|
||||
Django provides conditional ``GET`` handling via
|
||||
:class:`django.middleware.http.ConditionalGetMiddleware`. While being suitable
|
||||
for many situations, the middleware has limitations for advanced usage:
|
||||
|
||||
* It's applied globally to all views in your project.
|
||||
* It doesn't save you from generating the response, which may be expensive.
|
||||
|
|
|
@ -135,9 +135,9 @@ 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::
|
||||
If you want to generate more than one aggregate, you 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
|
||||
>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))
|
||||
|
|
|
@ -102,9 +102,9 @@ raises ``ValueError``::
|
|||
...
|
||||
ValueError: save() prohibited to prevent data loss due to unsaved related object 'place'.
|
||||
|
||||
Restaurant.objects.all() just returns the Restaurants, not the Places. Note
|
||||
that there are two restaurants - Ace Hardware the Restaurant was created in the
|
||||
call to r.place = p2::
|
||||
Restaurant.objects.all() returns the Restaurants, not the Places. Note that
|
||||
there are two restaurants - Ace Hardware the Restaurant was created in the call
|
||||
to r.place = p2::
|
||||
|
||||
>>> Restaurant.objects.all()
|
||||
<QuerySet [<Restaurant: Demon Dogs the restaurant>, <Restaurant: Ace Hardware the restaurant>]>
|
||||
|
|
|
@ -145,8 +145,8 @@ So these statements are all legal::
|
|||
|
||||
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.
|
||||
a model as you'd like. This is a non-repetitive way to define common "filters"
|
||||
for your models.
|
||||
|
||||
For example::
|
||||
|
||||
|
@ -396,7 +396,7 @@ manager, you can provide the default manager on the child class::
|
|||
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.
|
||||
still available, since it's inherited, but 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
|
||||
|
|
|
@ -265,7 +265,7 @@ By default, Django gives each model the following field::
|
|||
|
||||
This is an auto-incrementing primary key.
|
||||
|
||||
If you'd like to specify a custom primary key, just specify
|
||||
If you'd like to specify a custom primary key, 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.
|
||||
|
@ -436,8 +436,8 @@ should work; all are optional.
|
|||
Extra fields on many-to-many relationships
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When you're only dealing with simple many-to-many relationships such as
|
||||
mixing and matching pizzas and toppings, a standard
|
||||
When you're only dealing with 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.
|
||||
|
||||
|
@ -640,7 +640,7 @@ 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 file where your model is defined. Then,
|
||||
just refer to the other model class wherever needed. For example::
|
||||
refer to the other model class wherever needed. For example::
|
||||
|
||||
from django.db import models
|
||||
from geography.models import ZipCode
|
||||
|
@ -1218,7 +1218,7 @@ accessible through ``MyPerson``, and vice-versa::
|
|||
|
||||
You could also use a proxy model to define a different default ordering on
|
||||
a model. You might not always want to order the ``Person`` model, but regularly
|
||||
order by the ``last_name`` attribute when you use the proxy. This is easy::
|
||||
order by the ``last_name`` attribute when you use the proxy::
|
||||
|
||||
class OrderedPerson(Person):
|
||||
class Meta:
|
||||
|
|
|
@ -438,8 +438,8 @@ 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.
|
||||
``QuerySet`` "chain." 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::
|
||||
|
|
|
@ -53,7 +53,7 @@ Use standard DB optimization techniques
|
|||
|
||||
* Appropriate use of field types.
|
||||
|
||||
We will assume you have done the obvious things above. The rest of this document
|
||||
We will assume you have done the things listed 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
|
||||
|
@ -217,7 +217,7 @@ 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
|
||||
When you only want a ``dict`` or ``list`` of values, and don't need ORM model
|
||||
objects, make appropriate usage of
|
||||
:meth:`~django.db.models.query.QuerySet.values()`.
|
||||
These can be useful for replacing model objects in template code - as long as
|
||||
|
@ -260,7 +260,7 @@ But:
|
|||
Don't overuse ``count()`` and ``exists()``
|
||||
------------------------------------------
|
||||
|
||||
If you are going to need other data from the QuerySet, just evaluate it.
|
||||
If you are going to need other data from the QuerySet, evaluate it immediately.
|
||||
|
||||
For example, assuming an Email model that has a ``body`` attribute and a
|
||||
many-to-many relation to User, the following template code is optimal:
|
||||
|
|
|
@ -96,10 +96,10 @@ Saving ``ForeignKey`` and ``ManyToManyField`` fields
|
|||
----------------------------------------------------
|
||||
|
||||
Updating a :class:`~django.db.models.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``, assuming appropriate instances of ``Entry`` and
|
||||
``Blog`` are already saved to the database (so we can retrieve them below)::
|
||||
way as saving a normal field -- assign an object of the right type to the field
|
||||
in question. This example updates the ``blog`` attribute of an ``Entry``
|
||||
instance ``entry``, assuming appropriate instances of ``Entry`` and ``Blog``
|
||||
are already saved to the database (so we can retrieve them below)::
|
||||
|
||||
>>> from blog.models import Blog, Entry
|
||||
>>> entry = Entry.objects.get(pk=1)
|
||||
|
@ -365,9 +365,9 @@ Further filtering or ordering of a sliced queryset is prohibited due to the
|
|||
ambiguous nature of how that might work.
|
||||
|
||||
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::
|
||||
(e.g. ``SELECT foo FROM bar LIMIT 1``), use an 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]
|
||||
|
||||
|
@ -484,7 +484,7 @@ 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
|
||||
scenes. To span a relationship, use the field name of related fields
|
||||
across models, separated by double underscores, until you get to the field you
|
||||
want.
|
||||
|
||||
|
@ -495,7 +495,7 @@ is ``'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
|
||||
It works backwards, too. To refer to a "reverse" relationship, use the
|
||||
lowercase name of the model.
|
||||
|
||||
This example retrieves all ``Blog`` objects which have at least one ``Entry``
|
||||
|
@ -700,8 +700,8 @@ 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::
|
||||
For example, to retrieve all the entries that contain a percent sign, use the
|
||||
percent sign as any other character::
|
||||
|
||||
>>> Entry.objects.filter(headline__contains='%')
|
||||
|
||||
|
@ -746,8 +746,8 @@ 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
|
||||
:class:`~django.db.models.query.QuerySet` and reuse it::
|
||||
To avoid this problem, save the :class:`~django.db.models.query.QuerySet` and
|
||||
reuse it::
|
||||
|
||||
>>> queryset = Entry.objects.all()
|
||||
>>> print([p.headline for p in queryset]) # Evaluate the query set.
|
||||
|
@ -875,7 +875,7 @@ precede the definition of any keyword arguments. For example::
|
|||
Comparing objects
|
||||
=================
|
||||
|
||||
To compare two model instances, just use the standard Python comparison operator,
|
||||
To compare two model instances, use the standard Python comparison operator,
|
||||
the double equals sign: ``==``. Behind the scenes, that compares the primary
|
||||
key values of two models.
|
||||
|
||||
|
@ -954,7 +954,7 @@ Copying model instances
|
|||
|
||||
Although there is no built-in method for copying model instances, it is
|
||||
possible to easily create new instance with all fields' values copied. In the
|
||||
simplest case, you can just set ``pk`` to ``None``. Using our blog example::
|
||||
simplest case, you can set ``pk`` to ``None``. Using our blog example::
|
||||
|
||||
blog = Blog(name='My blog', tagline='Blogging is easy')
|
||||
blog.save() # blog.pk == 1
|
||||
|
@ -1040,8 +1040,8 @@ statement. It is a bulk operation for direct updates. It doesn't run any
|
|||
:attr:`~django.db.models.DateField.auto_now` field option.
|
||||
If you want to save every item in a :class:`~django.db.models.query.QuerySet`
|
||||
and make sure that the :meth:`~django.db.models.Model.save` method is called on
|
||||
each instance, you don't need any special function to handle that. Just loop
|
||||
over them and call :meth:`~django.db.models.Model.save`::
|
||||
each instance, you don't need any special function to handle that. Loop over
|
||||
them and call :meth:`~django.db.models.Model.save`::
|
||||
|
||||
for item in my_queryset:
|
||||
item.save()
|
||||
|
@ -1096,8 +1096,7 @@ Forward
|
|||
~~~~~~~
|
||||
|
||||
If a model has a :class:`~django.db.models.ForeignKey`, instances of that model
|
||||
will have access to the related (foreign) object via a simple attribute of the
|
||||
model.
|
||||
will have access to the related (foreign) object via an attribute of the model.
|
||||
|
||||
Example::
|
||||
|
||||
|
@ -1285,7 +1284,7 @@ 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
|
||||
that model will have access to the related object via an attribute of the
|
||||
model.
|
||||
|
||||
For example::
|
||||
|
|
|
@ -16,8 +16,8 @@ Use Cases
|
|||
Standard textual queries
|
||||
------------------------
|
||||
|
||||
Text-based fields have a selection of simple matching operations. For example,
|
||||
you may wish to allow lookup of an author like so::
|
||||
Text-based fields have a selection of matching operations. For example, you may
|
||||
wish to allow lookup up an author like so::
|
||||
|
||||
>>> Author.objects.filter(name__contains='Terry')
|
||||
[<Author: Terry Gilliam>, <Author: Terry Jones>]
|
||||
|
@ -77,7 +77,7 @@ enter something close (by varying definitions) to the source data.
|
|||
Document-based search
|
||||
---------------------
|
||||
|
||||
Simple database operations are too simple an approach when you start
|
||||
Standard database operations stop being a useful approach when you start
|
||||
considering large blocks of text. Whereas the examples above can be thought of
|
||||
as operations on a string of characters, full text search looks at the actual
|
||||
words. Depending on the system used, it's likely to use some of the following
|
||||
|
@ -109,8 +109,8 @@ your database and so can easily be combined with other relational queries such
|
|||
as categorization.
|
||||
|
||||
The :mod:`django.contrib.postgres` module provides some helpers to make these
|
||||
queries. For example, a simple query might be to select all the blog entries
|
||||
which mention "cheese"::
|
||||
queries. For example, a query might select all the blog entries which mention
|
||||
"cheese"::
|
||||
|
||||
>>> Entry.objects.filter(body_text__search='cheese')
|
||||
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]
|
||||
|
|
|
@ -46,8 +46,8 @@ return model instances:
|
|||
|
||||
This method takes a raw SQL query, executes it, and returns a
|
||||
``django.db.models.query.RawQuerySet`` instance. This ``RawQuerySet`` instance
|
||||
can be iterated over just like a normal
|
||||
:class:`~django.db.models.query.QuerySet` to provide object instances.
|
||||
can be iterated over like a normal :class:`~django.db.models.query.QuerySet` to
|
||||
provide object instances.
|
||||
|
||||
This is best illustrated with an example. Suppose you have the following model::
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ either all or none of the changes will be committed.
|
|||
generating a streaming response, since there's no sensible way to handle
|
||||
errors after starting to send the response.
|
||||
|
||||
In practice, this feature simply wraps every view function in the :func:`atomic`
|
||||
In practice, this feature wraps every view function in the :func:`atomic`
|
||||
decorator described below.
|
||||
|
||||
Note that only the execution of your view is enclosed in the transactions.
|
||||
|
@ -410,7 +410,7 @@ For instance, if your database connection is dropped because your process was
|
|||
killed without a chance to shut down gracefully, your rollback hook will never
|
||||
run.
|
||||
|
||||
The solution is simple: instead of doing something during the atomic block
|
||||
But there is a solution: instead of doing something during the atomic block
|
||||
(transaction) and then undoing it if the transaction fails, use
|
||||
:func:`on_commit` to delay doing it in the first place until after the
|
||||
transaction succeeds. It's a lot easier to undo something you never did in the
|
||||
|
@ -432,8 +432,8 @@ Low-level APIs
|
|||
Autocommit
|
||||
----------
|
||||
|
||||
Django provides a straightforward API in the :mod:`django.db.transaction`
|
||||
module to manage the autocommit state of each database connection.
|
||||
Django provides an API in the :mod:`django.db.transaction` module to manage the
|
||||
autocommit state of each database connection.
|
||||
|
||||
.. function:: get_autocommit(using=None)
|
||||
|
||||
|
@ -622,7 +622,7 @@ Handling exceptions within PostgreSQL transactions
|
|||
Inside a transaction, 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". While simple use of ``save()`` is unlikely
|
||||
until end of transaction block". While the basic 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.
|
||||
|
|
|
@ -5,11 +5,10 @@ Sending email
|
|||
.. module:: django.core.mail
|
||||
:synopsis: Helpers to easily send email.
|
||||
|
||||
Although Python makes sending email relatively easy via the :mod:`smtplib`
|
||||
Although Python provides a mail sending interface via the :mod:`smtplib`
|
||||
module, Django provides a couple of light wrappers over it. These wrappers are
|
||||
provided to make sending email extra quick, to make it easy to test email
|
||||
sending during development, and to provide support for platforms that can't use
|
||||
SMTP.
|
||||
provided to make sending email extra quick, to help test email sending during
|
||||
development, and to provide support for platforms that can't use SMTP.
|
||||
|
||||
The code lives in the ``django.core.mail`` module.
|
||||
|
||||
|
@ -45,8 +44,7 @@ a secure connection is used.
|
|||
|
||||
.. function:: send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None)
|
||||
|
||||
The simplest way to send email is using
|
||||
``django.core.mail.send_mail()``.
|
||||
In most cases, you can send email using ``django.core.mail.send_mail()``.
|
||||
|
||||
The ``subject``, ``message``, ``from_email`` and ``recipient_list`` parameters
|
||||
are required.
|
||||
|
@ -186,7 +184,7 @@ will not send the email. It's your responsibility to validate all data before
|
|||
passing it to the email functions.
|
||||
|
||||
If a ``message`` contains headers at the start of the string, the headers will
|
||||
simply be printed as the first bit of the email message.
|
||||
be printed as the first bit of the email 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
|
||||
|
@ -239,9 +237,9 @@ recipients, file attachments, or multi-part email, you'll need to create
|
|||
message itself. The :ref:`email backend <topic-email-backends>` is then
|
||||
responsible for sending the email.
|
||||
|
||||
For convenience, :class:`~django.core.mail.EmailMessage` provides a simple
|
||||
``send()`` method for sending a single email. If you need to send multiple
|
||||
messages, the email backend API :ref:`provides an alternative
|
||||
For convenience, :class:`~django.core.mail.EmailMessage` provides a ``send()``
|
||||
method for sending a single email. If you need to send multiple messages, the
|
||||
email backend API :ref:`provides an alternative
|
||||
<topics-sending-multiple-emails>`.
|
||||
|
||||
``EmailMessage`` Objects
|
||||
|
@ -360,7 +358,7 @@ The class has the following methods:
|
|||
* ``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::
|
||||
will be guessed from the filename. You can use it like this::
|
||||
|
||||
message.attach_file('/images/weather_map.png')
|
||||
|
||||
|
@ -672,9 +670,9 @@ 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 email headers and
|
||||
the email body. You then only need to set the :setting:`EMAIL_HOST` and
|
||||
This command will start a minimal SMTP server listening on port 1025 of
|
||||
localhost. This server prints to standard output all email headers and the
|
||||
email body. You then only need to set the :setting:`EMAIL_HOST` and
|
||||
:setting:`EMAIL_PORT` accordingly. For a more detailed discussion of SMTP
|
||||
server options, see the Python documentation for the :mod:`smtpd` module.
|
||||
|
||||
|
|
|
@ -79,8 +79,8 @@ The ``File`` object
|
|||
Internally, Django uses a :class:`django.core.files.File` instance any time it
|
||||
needs to represent a file.
|
||||
|
||||
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).
|
||||
Most of the time you'll 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::
|
||||
|
|
|
@ -569,8 +569,8 @@ 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::
|
||||
can override this method to add your own fields or even redefine the default
|
||||
fields/attributes of the order and deletion fields::
|
||||
|
||||
>>> from django.forms import BaseFormSet
|
||||
>>> from django.forms import formset_factory
|
||||
|
@ -651,9 +651,9 @@ This is useful if you want to :ref:`use more than one formset in a view
|
|||
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::
|
||||
Using a formset inside a view is not very different from 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::
|
||||
|
||||
from django.forms import formset_factory
|
||||
from django.shortcuts import render
|
||||
|
|
|
@ -26,11 +26,11 @@ allow a visitor to do things like enter text, select options, manipulate
|
|||
objects or controls, and so on, and then send that information back to the
|
||||
server.
|
||||
|
||||
Some of these form interface elements - text input or checkboxes - are fairly
|
||||
simple and are built into HTML itself. Others are much more complex; an
|
||||
interface that pops up a date picker or allows you to move a slider or
|
||||
manipulate controls will typically use JavaScript and CSS as well as HTML form
|
||||
``<input>`` elements to achieve these effects.
|
||||
Some of these form interface elements - text input or checkboxes - are built
|
||||
into HTML itself. Others are much more complex; an interface that pops up a
|
||||
date picker or allows you to move a slider or manipulate controls will
|
||||
typically use JavaScript and CSS as well as HTML form ``<input>`` elements to
|
||||
achieve these effects.
|
||||
|
||||
As well as its ``<input>`` elements, a form must specify two things:
|
||||
|
||||
|
@ -326,8 +326,7 @@ telling it where to go next.
|
|||
The template
|
||||
~~~~~~~~~~~~
|
||||
|
||||
We don't need to do much in our ``name.html`` template. The simplest example
|
||||
is:
|
||||
We don't need to do much in our ``name.html`` template:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
|
@ -671,8 +670,7 @@ Useful attributes on ``{{ field }}`` include:
|
|||
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.
|
||||
case, each object in the loop is a string containing the error message.
|
||||
|
||||
``{{ field.is_hidden }}``
|
||||
This attribute is ``True`` if the form field is a hidden field and
|
||||
|
|
|
@ -16,7 +16,7 @@ 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.
|
||||
in a form suitable for inclusion on your Web page.
|
||||
|
||||
.. admonition:: Assets and Django Admin
|
||||
|
||||
|
@ -49,7 +49,7 @@ The easiest way to define assets is as a static definition. Using this
|
|||
method, the declaration is an inner ``Media`` class. The properties of the
|
||||
inner class define the requirements.
|
||||
|
||||
Here's a simple example::
|
||||
Here's an example::
|
||||
|
||||
from django import forms
|
||||
|
||||
|
@ -362,8 +362,7 @@ are part of the form::
|
|||
<script type="text/javascript" src="http://static.example.com/whizbang.js"></script>
|
||||
|
||||
If you want to associate additional assets with a form -- for example,
|
||||
CSS for form layout -- simply add a ``Media`` declaration to the
|
||||
form::
|
||||
CSS for form layout -- add a ``Media`` declaration to the form::
|
||||
|
||||
>>> class ContactForm(forms.Form):
|
||||
... date = DateField(widget=CalendarWidget)
|
||||
|
|
|
@ -389,9 +389,8 @@ you've manually saved the instance produced by the form, you can invoke
|
|||
>>> 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:
|
||||
When you use a ``save()`` on a form, all data -- including many-to-many data --
|
||||
is saved without the need for any additional method calls. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -731,8 +730,8 @@ to make::
|
|||
>>> from myapp.models import Book
|
||||
>>> BookForm = modelform_factory(Book, fields=("author", "title"))
|
||||
|
||||
This can also be used to make simple modifications to existing forms, for
|
||||
example by specifying the widgets to be used for a given field::
|
||||
This can also be used to make modifications to existing forms, for example by
|
||||
specifying the widgets to be used for a given field::
|
||||
|
||||
>>> from django.forms import Textarea
|
||||
>>> Form = modelform_factory(Book, form=BookForm,
|
||||
|
@ -755,8 +754,8 @@ Model formsets
|
|||
.. class:: models.BaseModelFormSet
|
||||
|
||||
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::
|
||||
of enhanced formset classes to make working with Django models more
|
||||
convenient. Let's reuse the ``Author`` model from above::
|
||||
|
||||
>>> from django.forms import modelformset_factory
|
||||
>>> from myapp.models import Author
|
||||
|
@ -786,8 +785,8 @@ with the ``Author`` model. It works just like a regular formset::
|
|||
|
||||
:func:`~django.forms.models.modelformset_factory` uses
|
||||
:func:`~django.forms.formsets.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.
|
||||
means that a model formset is an extension of a basic formset that knows
|
||||
how to interact with a particular model.
|
||||
|
||||
Changing the queryset
|
||||
---------------------
|
||||
|
@ -952,7 +951,7 @@ extra forms displayed.
|
|||
|
||||
Also, ``extra=0`` doesn't prevent creation of new model instances as you can
|
||||
:ref:`add additional forms with JavaScript <understanding-the-managementform>`
|
||||
or just send additional POST data. Formsets `don't yet provide functionality
|
||||
or send additional POST data. Formsets `don't yet provide functionality
|
||||
<https://code.djangoproject.com/ticket/26142>`_ for an "edit only" view that
|
||||
prevents creation of new instances.
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ and in memory, and how to customize the default behavior.
|
|||
Basic file uploads
|
||||
==================
|
||||
|
||||
Consider a simple form containing a :class:`~django.forms.FileField`:
|
||||
Consider a form containing a :class:`~django.forms.FileField`:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: forms.py
|
||||
|
@ -42,9 +42,8 @@ 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:
|
||||
Most of the time, you'll pass the file data from ``request`` into the form as
|
||||
described in :ref:`binding-uploaded-files`. This would look something like:
|
||||
|
||||
.. code-block:: python
|
||||
:caption: views.py
|
||||
|
@ -107,9 +106,9 @@ corresponding :class:`~django.db.models.FileField` when calling
|
|||
form = ModelFormWithFileField()
|
||||
return render(request, 'upload.html', {'form': form})
|
||||
|
||||
If you are constructing an object manually, you can simply assign the file
|
||||
object from :attr:`request.FILES <django.http.HttpRequest.FILES>` to the file
|
||||
field in the model::
|
||||
If you are constructing an object manually, you can assign the file object from
|
||||
:attr:`request.FILES <django.http.HttpRequest.FILES>` to the file field in the
|
||||
model::
|
||||
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
|
@ -205,8 +204,8 @@ 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" which can be customized as described in the next section.
|
||||
These specifics -- 2.5 megabytes; ``/tmp``; etc. -- are "reasonable defaults"
|
||||
which can be customized as described in the next section.
|
||||
|
||||
Changing upload handler behavior
|
||||
--------------------------------
|
||||
|
@ -235,7 +234,7 @@ 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
|
||||
If you want to replace the upload handlers completely, you can assign a new
|
||||
list::
|
||||
|
||||
request.upload_handlers = [ProgressBarUploadHandler(request)]
|
||||
|
|
|
@ -379,7 +379,7 @@ convenience and security. If you wish to store more advanced data types
|
|||
including ``datetime`` and ``Decimal`` in JSON backed sessions, you will need
|
||||
to write a custom serializer (or convert such values to a JSON serializable
|
||||
object before storing them in ``request.session``). While serializing these
|
||||
values is fairly straightforward
|
||||
values is often straightforward
|
||||
(:class:`~django.core.serializers.json.DjangoJSONEncoder` may be helpful),
|
||||
writing a decoder that can reliably get back the same thing that you put in is
|
||||
more fragile. For example, you run the risk of returning a ``datetime`` that
|
||||
|
@ -444,10 +444,9 @@ 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 the
|
||||
:meth:`~backends.base.SessionBase.set_test_cookie` method of
|
||||
``request.session`` in a view, and call
|
||||
As a convenience, Django provides a way to test whether the user's browser
|
||||
accepts cookies. Call the :meth:`~backends.base.SessionBase.set_test_cookie`
|
||||
method of ``request.session`` in a view, and call
|
||||
:meth:`~backends.base.SessionBase.test_cookie_worked` in a subsequent view --
|
||||
not in the same view call.
|
||||
|
||||
|
@ -509,7 +508,7 @@ generating a ``session_key`` that collides with an existing one. ``create()``
|
|||
calls ``save()`` and loops until an unused ``session_key`` is generated.
|
||||
|
||||
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
|
||||
session is 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::
|
||||
|
||||
|
@ -701,9 +700,9 @@ In order to build a custom session engine or to customize an existing one, you
|
|||
may create a new class inheriting from :class:`~backends.base.SessionBase` or
|
||||
any other existing ``SessionStore`` class.
|
||||
|
||||
Extending most of the session engines is quite straightforward, but doing so
|
||||
with database-backed session engines generally requires some extra effort (see
|
||||
the next section for details).
|
||||
You can extend the session engines, but doing so with database-backed session
|
||||
engines generally requires some extra effort (see the next section for
|
||||
details).
|
||||
|
||||
.. _extending-database-backed-session-engines:
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ algorithm the system follows to determine which Python code to execute:
|
|||
one that matches the requested URL.
|
||||
|
||||
#. Once one of the URL patterns matches, Django imports and calls the given
|
||||
view, which is a simple Python function (or a :doc:`class-based view
|
||||
view, which is a Python function (or a :doc:`class-based view
|
||||
</topics/class-based-views/index>`). The view gets passed the following
|
||||
arguments:
|
||||
|
||||
|
@ -131,7 +131,7 @@ The following path converters are available by default:
|
|||
|
||||
* ``path`` - Matches any non-empty string, including the path separator,
|
||||
``'/'``. This allows you to match against a complete URL path rather than
|
||||
just a segment of a URL path as with ``str``.
|
||||
a segment of a URL path as with ``str``.
|
||||
|
||||
.. _registering-custom-path-converters:
|
||||
|
||||
|
@ -679,13 +679,13 @@ instances of an application are deployed. In other words, since multiple
|
|||
instances of a single application will share named URLs, namespaces provide a
|
||||
way to tell these named URLs apart.
|
||||
|
||||
Django applications that make proper use of URL namespacing can be deployed more
|
||||
than once for a particular site. For example :mod:`django.contrib.admin` has an
|
||||
:class:`~django.contrib.admin.AdminSite` class which allows you to easily
|
||||
:ref:`deploy more than one instance of the admin <multiple-admin-sites>`.
|
||||
In a later example, we'll discuss the idea of deploying the polls application
|
||||
from the tutorial in two different locations so we can serve the same
|
||||
functionality to two different audiences (authors and publishers).
|
||||
Django applications that make proper use of URL namespacing can be deployed
|
||||
more than once for a particular site. For example :mod:`django.contrib.admin`
|
||||
has an :class:`~django.contrib.admin.AdminSite` class which allows you to
|
||||
:ref:`deploy more than one instance of the admin <multiple-admin-sites>`. In a
|
||||
later example, we'll discuss the idea of deploying the polls application from
|
||||
the tutorial in two different locations so we can serve the same functionality
|
||||
to two different audiences (authors and publishers).
|
||||
|
||||
A URL namespace comes in two parts, both of which are strings:
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
Writing views
|
||||
=============
|
||||
|
||||
A view function, or *view* for short, is simply a Python function that takes a
|
||||
A view function, or *view* for short, is 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
|
||||
|
@ -60,12 +60,12 @@ date and time. To display this view at a particular URL, you'll need to create a
|
|||
Returning errors
|
||||
================
|
||||
|
||||
Returning HTTP error codes in Django is easy. There are subclasses of
|
||||
Django provides help for returning HTTP error codes. 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
|
||||
documentation. Return an instance of one of those subclasses instead of a
|
||||
normal :class:`~django.http.HttpResponse` in order to signify an error. For
|
||||
example::
|
||||
|
||||
from django.http import HttpResponse, HttpResponseNotFound
|
||||
|
@ -138,9 +138,9 @@ Customizing error views
|
|||
=======================
|
||||
|
||||
The default error views in Django should suffice for most Web applications,
|
||||
but can easily be overridden if you need any custom behavior. Simply specify
|
||||
the handlers as seen below in your URLconf (setting them anywhere else will
|
||||
have no effect).
|
||||
but can easily be overridden if you need any custom behavior. Specify the
|
||||
handlers as seen below in your URLconf (setting them anywhere else will have no
|
||||
effect).
|
||||
|
||||
The :func:`~django.views.defaults.page_not_found` view is overridden by
|
||||
:data:`~django.conf.urls.handler404`::
|
||||
|
|
|
@ -45,8 +45,8 @@ locales when guessing the format used by the user when inputting data on forms.
|
|||
``%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::
|
||||
To enable a form field to localize input and output data use its ``localize``
|
||||
argument::
|
||||
|
||||
class CashRegisterForm(forms.Form):
|
||||
product = forms.CharField()
|
||||
|
@ -152,8 +152,8 @@ 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, specify the path where you'll place format files
|
||||
first. To do that, just set your :setting:`FORMAT_MODULE_PATH` setting to
|
||||
the package where format files will exist, for instance::
|
||||
first. To do that, set your :setting:`FORMAT_MODULE_PATH` setting to the
|
||||
package where format files will exist, for instance::
|
||||
|
||||
FORMAT_MODULE_PATH = [
|
||||
'mysite.formats',
|
||||
|
|
|
@ -28,9 +28,9 @@ Essentially, Django does two things:
|
|||
* It uses these hooks to localize Web apps for particular users according to
|
||||
their preferences.
|
||||
|
||||
Obviously, translation depends on the target language, and formatting usually
|
||||
depends on the target country. This information is provided by browsers in
|
||||
the ``Accept-Language`` header. However, the time zone isn't readily available.
|
||||
Translation depends on the target language, and formatting usually depends on
|
||||
the target country. This information is provided by browsers in the
|
||||
``Accept-Language`` header. However, the time zone isn't readily available.
|
||||
|
||||
Definitions
|
||||
===========
|
||||
|
|
|
@ -62,8 +62,8 @@ You can use :func:`~django.utils.timezone.is_aware` and
|
|||
aware or naive.
|
||||
|
||||
When time zone support is disabled, Django uses naive datetime objects in local
|
||||
time. This is simple and sufficient for many use cases. In this mode, to obtain
|
||||
the current time, you would write::
|
||||
time. This is sufficient for many use cases. In this mode, to obtain the
|
||||
current time, you would write::
|
||||
|
||||
import datetime
|
||||
|
||||
|
@ -155,11 +155,11 @@ time zone automatically. Instead, Django provides :ref:`time zone selection
|
|||
functions <time-zone-selection-functions>`. Use them to build the time zone
|
||||
selection logic that makes sense for you.
|
||||
|
||||
Most websites that care about time zones just ask users in which time zone they
|
||||
live and store this information in the user's profile. For anonymous users,
|
||||
they use the time zone of their primary audience or UTC. pytz_ provides
|
||||
helpers_, like a list of time zones per country, that you can use to pre-select
|
||||
the most likely choices.
|
||||
Most websites that care about time zones ask users in which time zone they live
|
||||
and store this information in the user's profile. For anonymous users, they use
|
||||
the time zone of their primary audience or UTC. pytz_ provides helpers_, like a
|
||||
list of time zones per country, that you can use to pre-select the most likely
|
||||
choices.
|
||||
|
||||
Here's an example that stores the current timezone in the session. (It skips
|
||||
error handling entirely for the sake of simplicity.)
|
||||
|
@ -437,7 +437,7 @@ When serializing an aware datetime, the UTC offset is included, like this::
|
|||
|
||||
"2011-09-01T13:20:30+03:00"
|
||||
|
||||
For a naive datetime, it obviously isn't::
|
||||
While for a naive datetime, it isn't::
|
||||
|
||||
"2011-09-01T13:20:30"
|
||||
|
||||
|
@ -451,8 +451,8 @@ zone support, you'll see :exc:`RuntimeWarning`\ s when you load them. To get
|
|||
rid of the warnings, you must convert your fixtures to the "aware" format.
|
||||
|
||||
You can regenerate fixtures with :djadmin:`loaddata` then :djadmin:`dumpdata`.
|
||||
Or, if they're small enough, you can simply edit them to add the UTC offset
|
||||
that matches your :setting:`TIME_ZONE` to each serialized datetime.
|
||||
Or, if they're small enough, you can edit them to add the UTC offset that
|
||||
matches your :setting:`TIME_ZONE` to each serialized datetime.
|
||||
|
||||
.. _time-zones-faq:
|
||||
|
||||
|
@ -470,8 +470,8 @@ Setup
|
|||
|
||||
When you enable time zone support, you'll encounter some errors because
|
||||
you're using naive datetimes where Django expects aware datetimes. Such
|
||||
errors show up when running tests and they're easy to fix. You'll quickly
|
||||
learn how to avoid invalid operations.
|
||||
errors show up when running tests. You'll quickly learn how to avoid invalid
|
||||
operations.
|
||||
|
||||
On the other hand, bugs caused by the lack of time zone support are much
|
||||
harder to prevent, diagnose and fix. Anything that involves scheduled tasks
|
||||
|
@ -613,7 +613,7 @@ Troubleshooting
|
|||
|
||||
>>> from django.utils import timezone
|
||||
>>> timezone.activate(pytz.timezone("Asia/Singapore"))
|
||||
# For this example, we just set the time zone to Singapore, but here's how
|
||||
# For this example, we set the time zone to Singapore, but here's how
|
||||
# you would obtain the current time zone in the general case.
|
||||
>>> current_tz = timezone.get_current_timezone()
|
||||
# Again, this is the correct way to convert between time zones with pytz.
|
||||
|
|
|
@ -91,8 +91,8 @@ string::
|
|||
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::
|
||||
You could code this without using the alias. This example is identical to the
|
||||
previous one::
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.utils.translation import gettext
|
||||
|
@ -439,8 +439,8 @@ strings before passing them to non-Django code::
|
|||
|
||||
requests.post('https://example.com/send', data={'body': str(body)})
|
||||
|
||||
If you don't like the long ``gettext_lazy`` name, you can just alias it as
|
||||
``_`` (underscore), like so::
|
||||
If you don't like the long ``gettext_lazy`` name, you can alias it as ``_``
|
||||
(underscore), like so::
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
@ -928,7 +928,7 @@ view <set_language-redirect-view>` for an example of how to display a language
|
|||
selector using ``{% get_language_info_list %}``.
|
||||
|
||||
In addition to :setting:`LANGUAGES` style list of tuples,
|
||||
``{% get_language_info_list %}`` supports simple lists of language codes.
|
||||
``{% get_language_info_list %}`` supports lists of language codes.
|
||||
If you do this in your view:
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -949,7 +949,7 @@ you can iterate over those languages in the template::
|
|||
Template filters
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
There are also simple filters available for convenience:
|
||||
There are also some filters available for convenience:
|
||||
|
||||
* ``{{ LANGUAGE_CODE|language_name }}`` ("German")
|
||||
* ``{{ LANGUAGE_CODE|language_name_local }}`` ("Deutsch")
|
||||
|
@ -1048,7 +1048,7 @@ Using the JavaScript translation catalog
|
|||
|
||||
.. highlightlang:: javascript
|
||||
|
||||
To use the catalog, just pull in the dynamically generated script like this:
|
||||
To use the catalog, pull in the dynamically generated script like this:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
|
@ -1565,9 +1565,9 @@ multiple times::
|
|||
|
||||
If you don't have the ``gettext`` utilities installed,
|
||||
:djadmin:`makemessages` will create empty files. If that's the case, either
|
||||
install the ``gettext`` utilities or just copy the English message file
|
||||
install the ``gettext`` utilities or 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.
|
||||
point, which is an empty translation file.
|
||||
|
||||
.. admonition:: Working on Windows?
|
||||
|
||||
|
@ -1575,11 +1575,10 @@ multiple times::
|
|||
:djadmin:`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.
|
||||
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** -- 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::
|
||||
|
@ -1693,7 +1692,7 @@ djangojs`` parameter, like this::
|
|||
django-admin makemessages -d djangojs -l de
|
||||
|
||||
This would create or update the message file for JavaScript for German. After
|
||||
updating message files, just run :djadmin:`django-admin compilemessages
|
||||
updating message files, run :djadmin:`django-admin compilemessages
|
||||
<compilemessages>` the same way as you do with normal Django message files.
|
||||
|
||||
.. _gettext_on_windows:
|
||||
|
@ -1702,9 +1701,9 @@ updating message files, just run :djadmin:`django-admin compilemessages
|
|||
----------------------
|
||||
|
||||
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, download `a precompiled binary
|
||||
message files (``.po``). Translation work itself 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, download `a precompiled binary
|
||||
installer <https://mlocati.github.io/articles/gettext-iconv-windows.html>`_.
|
||||
|
||||
You may also use ``gettext`` binaries you have obtained elsewhere, so long as
|
||||
|
@ -1935,9 +1934,9 @@ way Django does translation:
|
|||
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.
|
||||
Once you've prepared your translations -- or, if you want to use the
|
||||
translations that come with Django -- you'll 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.
|
||||
|
@ -2042,7 +2041,7 @@ Notes:
|
|||
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::
|
||||
code. Here's an example::
|
||||
|
||||
from django.http import HttpResponse
|
||||
|
||||
|
@ -2098,8 +2097,8 @@ of the generic language. For example, untranslated ``pt_BR`` strings use ``pt``
|
|||
translations.
|
||||
|
||||
This way, you can write applications that include their own translations, and
|
||||
you can override base translations in your project. Or, you can just build
|
||||
a big project out of several apps and put all translations into one big common
|
||||
you can override base translations in your project. Or, you can build a big
|
||||
project out of several apps and put all translations into one big common
|
||||
message file specific to the project you are composing. The choice is yours.
|
||||
|
||||
All message file repositories are structured the same way. They are:
|
||||
|
|
|
@ -72,10 +72,10 @@ sure a database server is running. Django supports many different database
|
|||
servers and is officially supported with PostgreSQL_, MariaDB_, MySQL_, Oracle_
|
||||
and SQLite_.
|
||||
|
||||
If you are developing a simple project or something you don't plan to deploy
|
||||
in a production environment, SQLite is generally the simplest option as it
|
||||
doesn't require running a separate server. However, SQLite has many differences
|
||||
from other databases, so if you are working on something substantial, it's
|
||||
If you are developing a small project or something you don't plan to deploy in
|
||||
a production environment, SQLite is generally the best option as it doesn't
|
||||
require running a separate server. However, SQLite has many differences from
|
||||
other databases, so if you are working on something substantial, it's
|
||||
recommended to develop with the same database that you plan on using in
|
||||
production.
|
||||
|
||||
|
@ -107,10 +107,10 @@ If you plan to use Django's ``manage.py migrate`` command to automatically
|
|||
create database tables for your models (after first installing Django and
|
||||
creating a project), 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. After creating a database user with these
|
||||
permissions, you'll specify the details in your project's settings file,
|
||||
see :setting:`DATABASES` for details.
|
||||
the tables, you can grant Django ``SELECT``, ``INSERT``, ``UPDATE`` and
|
||||
``DELETE`` permissions. After creating a database user with these permissions,
|
||||
you'll specify the details in your project's settings file, see
|
||||
:setting:`DATABASES` for details.
|
||||
|
||||
If you're using Django's :doc:`testing framework</topics/testing/index>` to test
|
||||
database queries, Django will need permission to create a test database.
|
||||
|
@ -132,8 +132,6 @@ 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-official-release:
|
||||
|
||||
Installing an official release with ``pip``
|
||||
|
@ -171,7 +169,7 @@ 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; however, these packages will rarely
|
||||
of dependencies and supported upgrade paths; however, these packages will rarely
|
||||
contain the latest release of Django.
|
||||
|
||||
.. _installing-development-version:
|
||||
|
@ -221,8 +219,8 @@ latest bug fixes and improvements, follow these instructions:
|
|||
``django-admin`` utility command available. In other words, you're all
|
||||
set!
|
||||
|
||||
When you want to update your copy of the Django source code, just run the
|
||||
command ``git pull`` from within the ``django`` directory. When you do this,
|
||||
Git will automatically download any changes.
|
||||
When you want to update your copy of the Django source code, run the command
|
||||
``git pull`` from within the ``django`` directory. When you do this, Git will
|
||||
download any changes.
|
||||
|
||||
.. _Git: https://git-scm.com/
|
||||
|
|
|
@ -122,7 +122,7 @@ Using logging
|
|||
|
||||
Once you have configured your loggers, handlers, filters and
|
||||
formatters, you need to place logging calls into your code. Using the
|
||||
logging framework is very simple. Here's an example::
|
||||
logging framework works like this::
|
||||
|
||||
# import the logging library
|
||||
import logging
|
||||
|
@ -239,7 +239,7 @@ The full documentation for :ref:`dictConfig format <logging-config-dictschema>`
|
|||
is the best source of information about logging configuration dictionaries.
|
||||
However, to give you a taste of what is possible, here are several examples.
|
||||
|
||||
First, here's a simple configuration which writes all logging from the
|
||||
First, here's a configuration which writes all logging from the
|
||||
:ref:`django-logger` logger to a local file::
|
||||
|
||||
.. code-block:: python
|
||||
|
@ -363,8 +363,8 @@ This logging configuration does the following things:
|
|||
|
||||
* Defines two formatters:
|
||||
|
||||
* ``simple``, that just outputs the log level name (e.g.,
|
||||
``DEBUG``) and the log message.
|
||||
* ``simple``, that outputs the log level name (e.g., ``DEBUG``) and the log
|
||||
message.
|
||||
|
||||
The ``format`` string is a normal Python formatting string
|
||||
describing the details that are to be output on each logging
|
||||
|
|
|
@ -114,8 +114,8 @@ Django projects without the need for a full database.
|
|||
Workflow
|
||||
========
|
||||
|
||||
Working with migrations is simple. Make changes to your models - say, add
|
||||
a field and remove a model - and then run :djadmin:`makemigrations`::
|
||||
Django can create migrations for you. Make changes to your models - say, add a
|
||||
field and remove a model - and then run :djadmin:`makemigrations`::
|
||||
|
||||
$ python manage.py makemigrations
|
||||
Migrations for 'books':
|
||||
|
@ -173,10 +173,10 @@ Dependencies
|
|||
============
|
||||
|
||||
While migrations are per-app, the tables and relationships implied by
|
||||
your models are too complex to be created for just one app at a time. When
|
||||
you make a migration that requires something else to run - for example,
|
||||
you add a ``ForeignKey`` in your ``books`` app to your ``authors`` app - the
|
||||
resulting migration will contain a dependency on a migration in ``authors``.
|
||||
your models are too complex to be created for one app at a time. When you make
|
||||
a migration that requires something else to run - for example, you add a
|
||||
``ForeignKey`` in your ``books`` app to your ``authors`` app - the resulting
|
||||
migration will contain a dependency on a migration in ``authors``.
|
||||
|
||||
This means that when you run the migrations, the ``authors`` migration runs
|
||||
first and creates the table the ``ForeignKey`` references, and then the migration
|
||||
|
@ -201,8 +201,8 @@ Migration files
|
|||
===============
|
||||
|
||||
Migrations are stored as an on-disk format, referred to here as
|
||||
"migration files". These files are actually just normal Python files with
|
||||
an agreed-upon object layout, written in a declarative style.
|
||||
"migration files". These files are actually normal Python files with an
|
||||
agreed-upon object layout, written in a declarative style.
|
||||
|
||||
A basic migration file looks like this::
|
||||
|
||||
|
@ -286,9 +286,8 @@ Initial migrations
|
|||
.. attribute:: Migration.initial
|
||||
|
||||
The "initial migrations" for an app are the migrations that create the first
|
||||
version of that app's tables. Usually an app will have just one initial
|
||||
migration, but in some cases of complex model interdependencies it may have two
|
||||
or more.
|
||||
version of that app's tables. Usually an app will have one initial migration,
|
||||
but in some cases of complex model interdependencies it may have two or more.
|
||||
|
||||
Initial migrations are marked with an ``initial = True`` class attribute on the
|
||||
migration class. If an ``initial`` class attribute isn't found, a migration
|
||||
|
@ -322,13 +321,12 @@ new migrations until it's fixed. When using multiple databases, you can use the
|
|||
Adding migrations to apps
|
||||
=========================
|
||||
|
||||
Adding migrations to new apps is straightforward - they come preconfigured to
|
||||
accept migrations, and so just run :djadmin:`makemigrations` once you've made
|
||||
some changes.
|
||||
New apps come preconfigured to accept migrations, and so you can add migrations
|
||||
by running :djadmin:`makemigrations` once you've made some changes.
|
||||
|
||||
If your app already has models and database tables, and doesn't have migrations
|
||||
yet (for example, you created it against a previous Django version), you'll
|
||||
need to convert it to use migrations; this is a simple process::
|
||||
need to convert it to use migrations by running::
|
||||
|
||||
$ python manage.py makemigrations your_app_label
|
||||
|
||||
|
@ -390,8 +388,8 @@ classes will need to be kept around for as long as there is a migration
|
|||
referencing them. Any :doc:`custom model fields </howto/custom-model-fields>`
|
||||
will also need to be kept, since these are imported directly by migrations.
|
||||
|
||||
In addition, the base classes of the model are just stored as pointers, so you
|
||||
must always keep base classes around for as long as there is a migration that
|
||||
In addition, the base classes of the model are stored as pointers, so you must
|
||||
always keep base classes around for as long as there is a migration that
|
||||
contains a reference to them. On the plus side, methods and managers from these
|
||||
base classes inherit normally, so if you absolutely need access to these you
|
||||
can opt to move them into a superclass.
|
||||
|
@ -492,10 +490,10 @@ second is a :doc:`SchemaEditor </ref/schema-editor>`, which you can use to
|
|||
manually effect database schema changes (but beware, doing this can confuse
|
||||
the migration autodetector!)
|
||||
|
||||
Let's write a simple migration that populates our new ``name`` field with the
|
||||
combined values of ``first_name`` and ``last_name`` (we've come to our senses
|
||||
and realized that not everyone has first and last names). All we
|
||||
need to do is use the historical model and iterate over the rows::
|
||||
Let's write a migration that populates our new ``name`` field with the combined
|
||||
values of ``first_name`` and ``last_name`` (we've come to our senses and
|
||||
realized that not everyone has first and last names). All we need to do is use
|
||||
the historical model and iterate over the rows::
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
@ -517,8 +515,8 @@ need to do is use the historical model and iterate over the rows::
|
|||
migrations.RunPython(combine_names),
|
||||
]
|
||||
|
||||
Once that's done, we can just run ``python manage.py migrate`` as normal and
|
||||
the data migration will run in place alongside other migrations.
|
||||
Once that's done, we can run ``python manage.py migrate`` as normal and the
|
||||
data migration will run in place alongside other migrations.
|
||||
|
||||
You can pass a second callable to
|
||||
:class:`~django.db.migrations.operations.RunPython` to run whatever logic you
|
||||
|
@ -593,18 +591,17 @@ so they can coexist with the old migration files, and Django will intelligently
|
|||
switch between them depending where you are in the history. If you're still
|
||||
part-way through the set of migrations that you squashed, it will keep using
|
||||
them until it hits the end and then switch to the squashed history, while new
|
||||
installs will just use the new squashed migration and skip all the old ones.
|
||||
installs will use the new squashed migration and skip all the old ones.
|
||||
|
||||
This enables you to squash and not mess up systems currently in production
|
||||
that aren't fully up-to-date yet. The recommended process is to squash, keeping
|
||||
the old files, commit and release, wait until all systems are upgraded with
|
||||
the new release (or if you're a third-party project, just ensure your users
|
||||
upgrade releases in order without skipping any), and then remove the old files,
|
||||
commit and do a second release.
|
||||
the new release (or if you're a third-party project, ensure your users upgrade
|
||||
releases in order without skipping any), and then remove the old files, commit
|
||||
and do a second release.
|
||||
|
||||
The command that backs all this is :djadmin:`squashmigrations` - just pass
|
||||
it the app label and migration name you want to squash up to, and it'll get to
|
||||
work::
|
||||
The command that backs all this is :djadmin:`squashmigrations` - pass it the
|
||||
app label and migration name you want to squash up to, and it'll get to work::
|
||||
|
||||
$ ./manage.py squashmigrations myapp 0004
|
||||
Will squash the following migrations:
|
||||
|
@ -660,7 +657,7 @@ You must then transition the squashed migration to a normal migration by:
|
|||
Serializing values
|
||||
==================
|
||||
|
||||
Migrations are just Python files containing the old definitions of your models
|
||||
Migrations are Python files containing the old definitions of your models
|
||||
- thus, to write them, Django must take the current state of your models and
|
||||
serialize them out into a file.
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ Get things right from the start
|
|||
-------------------------------
|
||||
|
||||
Some work in optimization involves tackling performance shortcomings, but some
|
||||
of the work can simply be built in to what you'd do anyway, as part of the good
|
||||
of the work can be built in to what you'd do anyway, as part of the good
|
||||
practices you should adopt even before you start thinking about improving
|
||||
performance.
|
||||
|
||||
|
@ -353,7 +353,7 @@ Newer is often - but not always - better
|
|||
It's fairly rare for a new release of well-maintained software to be less
|
||||
efficient, but the maintainers can't anticipate every possible use-case - so
|
||||
while being aware that newer versions are likely to perform better, don't
|
||||
simply assume that they always will.
|
||||
assume that they always will.
|
||||
|
||||
This is true of Django itself. Successive releases have offered a number of
|
||||
improvements across the system, but you should still check the real-world
|
||||
|
|
|
@ -66,10 +66,10 @@ this if you know what you are doing. There are other :ref:`limitations
|
|||
control.
|
||||
|
||||
:ref:`CSRF protection works <how-csrf-works>` by checking for a secret in each
|
||||
POST request. This ensures that a malicious user cannot simply "replay" a form
|
||||
POST to your website and have another logged in user unwittingly submit that
|
||||
form. The malicious user would have to know the secret, which is user specific
|
||||
(using a cookie).
|
||||
POST request. This ensures that a malicious user cannot "replay" a form POST to
|
||||
your website and have another logged in user unwittingly submit that form. The
|
||||
malicious user would have to know the secret, which is user specific (using a
|
||||
cookie).
|
||||
|
||||
When deployed with :ref:`HTTPS <security-recommendation-ssl>`,
|
||||
``CsrfViewMiddleware`` will check that the HTTP referer header is set to a
|
||||
|
|
|
@ -15,7 +15,7 @@ serializer to handle any format (text-based or not).
|
|||
Serializing data
|
||||
================
|
||||
|
||||
At the highest level, serializing data is a very simple operation::
|
||||
At the highest level, you can serialize data like this::
|
||||
|
||||
from django.core import serializers
|
||||
data = serializers.serialize("xml", SomeModel.objects.all())
|
||||
|
@ -74,7 +74,7 @@ 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
|
||||
that model. 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.
|
||||
|
||||
|
@ -105,7 +105,7 @@ serialize the ``Place`` models as well::
|
|||
Deserializing data
|
||||
==================
|
||||
|
||||
Deserializing data is also a fairly simple operation::
|
||||
Deserializing data is very similar to serializing it::
|
||||
|
||||
for obj in serializers.deserialize("xml", data):
|
||||
do_something_with(obj)
|
||||
|
@ -114,7 +114,7 @@ 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
|
||||
``deserialize`` iterator *aren't* regular Django objects. Instead, they are
|
||||
special ``DeserializedObject`` instances that wrap a created -- but unsaved --
|
||||
object and any associated relationship data.
|
||||
|
||||
|
@ -136,7 +136,7 @@ something like::
|
|||
|
||||
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.
|
||||
trust your data source you can instead save the object directly and move on.
|
||||
|
||||
The Django object itself can be inspected as ``deserialized_object.object``.
|
||||
If fields in the serialized data do not exist on a model, a
|
||||
|
@ -170,7 +170,7 @@ Identifier Information
|
|||
XML
|
||||
---
|
||||
|
||||
The basic XML serialization format is quite simple::
|
||||
The basic XML serialization format looks like this::
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<django-objects version="1.0">
|
||||
|
@ -247,7 +247,7 @@ with three properties: "pk", "model" and "fields". "fields" is again an object
|
|||
containing each field's name and value as property and property-value
|
||||
respectively.
|
||||
|
||||
Foreign keys just have the PK of the linked object as property value.
|
||||
Foreign keys have the PK of the linked object as property value.
|
||||
ManyToMany-relations are serialized for the model that defines them and are
|
||||
represented as a list of PKs.
|
||||
|
||||
|
@ -313,7 +313,7 @@ again a mapping with the key being name of the field and the value the value::
|
|||
model: sessions.session
|
||||
pk: 4b678b301dfd8a4e0dad910de3ae245b
|
||||
|
||||
Referential fields are again just represented by the PK or sequence of PKs.
|
||||
Referential fields are again represented by the PK or sequence of PKs.
|
||||
|
||||
.. _topics-serialization-natural-keys:
|
||||
|
||||
|
|
|
@ -104,9 +104,8 @@ 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.
|
||||
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.
|
||||
|
||||
|
@ -161,7 +160,7 @@ Creating your own settings
|
|||
==========================
|
||||
|
||||
There's nothing stopping you from creating your own settings, for your own
|
||||
Django apps. Just follow these guidelines:
|
||||
Django apps, but follow these guidelines:
|
||||
|
||||
* Setting names must be all uppercase.
|
||||
* Don't reinvent an already-existing setting.
|
||||
|
@ -248,7 +247,7 @@ 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. There is a property just for this
|
||||
that settings have already been configured. There is a property for this
|
||||
purpose:
|
||||
|
||||
.. attribute: django.conf.settings.configured
|
||||
|
|
|
@ -138,7 +138,7 @@ Now, our ``my_callback`` function will be called each time a request finishes.
|
|||
submodule of the application they relate to. Signal receivers are
|
||||
connected in the :meth:`~django.apps.AppConfig.ready` method of your
|
||||
application configuration class. If you're using the :func:`receiver`
|
||||
decorator, simply import the ``signals`` submodule inside
|
||||
decorator, import the ``signals`` submodule inside
|
||||
:meth:`~django.apps.AppConfig.ready`.
|
||||
|
||||
.. note::
|
||||
|
|
|
@ -225,7 +225,7 @@ subdirectories as needed.
|
|||
Do this for your own sanity. Storing all templates in the root level of a
|
||||
single directory gets messy.
|
||||
|
||||
To load a template that's within a subdirectory, just use a slash, like so::
|
||||
To load a template that's within a subdirectory, use a slash, like so::
|
||||
|
||||
get_template('news/story_detail.html')
|
||||
|
||||
|
@ -439,7 +439,7 @@ adds defaults that differ from Jinja2's for a few options:
|
|||
* Using the result multiple times in each template.
|
||||
|
||||
Unless all of these conditions are met, passing a function to the template is
|
||||
simpler and more in line with the design of Jinja2.
|
||||
more in line with the design of Jinja2.
|
||||
|
||||
The default configuration is purposefully kept to a minimum. If a template is
|
||||
rendered with a request (e.g. when using :py:func:`~django.shortcuts.render`),
|
||||
|
@ -478,10 +478,10 @@ Then you could use the following constructs in Jinja2 templates:
|
|||
The concepts of tags and filters exist both in the Django template language
|
||||
and in Jinja2 but they're used differently. Since Jinja2 supports passing
|
||||
arguments to callables in templates, many features that require a template tag
|
||||
or filter in Django templates can be achieved simply by calling a function in
|
||||
Jinja2 templates, as shown in the example above. Jinja2's global namespace
|
||||
removes the need for template context processors. The Django template language
|
||||
doesn't have an equivalent of Jinja2 tests.
|
||||
or filter in Django templates can be achieved by calling a function in Jinja2
|
||||
templates, as shown in the example above. Jinja2's global namespace removes the
|
||||
need for template context processors. The Django template language doesn't have
|
||||
an equivalent of Jinja2 tests.
|
||||
|
||||
Custom backends
|
||||
---------------
|
||||
|
@ -667,9 +667,9 @@ Syntax
|
|||
This is an overview of the Django template language's syntax. For details
|
||||
see the :doc:`language syntax reference </ref/templates/language>`.
|
||||
|
||||
A Django template is simply a text document or a Python string marked-up using
|
||||
the Django template language. Some constructs are recognized and interpreted
|
||||
by the template engine. The main ones are variables and tags.
|
||||
A Django template is a text document or a Python string marked-up using the
|
||||
Django template language. Some constructs are recognized and interpreted by the
|
||||
template engine. The main ones are variables and tags.
|
||||
|
||||
A template is rendered with a context. Rendering replaces variables with their
|
||||
values, which are looked up in the context, and executes tags. Everything else
|
||||
|
@ -822,8 +822,8 @@ data to be added to the rendering context.
|
|||
Their main use is to add common data shared by all templates to the context
|
||||
without repeating code in every view.
|
||||
|
||||
Django provides many :ref:`built-in context processors <context-processors>`.
|
||||
Implementing a custom context processor is as simple as defining a function.
|
||||
Django provides many :ref:`built-in context processors <context-processors>`,
|
||||
and you can implement your own additional context processors, too.
|
||||
|
||||
.. _Jinja2: http://jinja.pocoo.org/
|
||||
.. _DEP 182: https://github.com/django/deps/blob/master/final/0182-multiple-template-engines.rst
|
||||
|
|
|
@ -35,7 +35,7 @@ restricted subset of the test client API:
|
|||
Example
|
||||
-------
|
||||
|
||||
The following is a simple unit test using the request factory::
|
||||
The following is a unit test using the request factory::
|
||||
|
||||
from django.contrib.auth.models import AnonymousUser, User
|
||||
from django.test import RequestFactory, TestCase
|
||||
|
@ -79,9 +79,8 @@ Projects that support multitenancy or otherwise alter business logic based on
|
|||
the request's host and use custom host names in tests must include those hosts
|
||||
in :setting:`ALLOWED_HOSTS`.
|
||||
|
||||
The first and simplest option to do so is to add the hosts to your settings
|
||||
file. For example, the test suite for docs.djangoproject.com includes the
|
||||
following::
|
||||
The first option to do so is to add the hosts to your settings file. For
|
||||
example, the test suite for docs.djangoproject.com includes the following::
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ 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.
|
||||
|
||||
The preferred way to write tests in Django is using the :mod:`unittest` module
|
||||
built in to the Python standard library. This is covered in detail in the
|
||||
:doc:`overview` document.
|
||||
|
|
|
@ -661,7 +661,7 @@ More details are in :ref:`explicitly-setting-the-active-language`.
|
|||
Example
|
||||
-------
|
||||
|
||||
The following is a simple unit test using the test client::
|
||||
The following is a unit test using the test client::
|
||||
|
||||
import unittest
|
||||
from django.test import Client
|
||||
|
@ -702,11 +702,11 @@ Normal Python unit test classes extend a base class of
|
|||
|
||||
Hierarchy of Django unit testing classes
|
||||
|
||||
Converting a normal :class:`unittest.TestCase` to any of the subclasses is
|
||||
easy: change the base class of your test from ``unittest.TestCase`` to the
|
||||
subclass. All of the standard Python unit test functionality will be available,
|
||||
and it will be augmented with some useful additions as described in each
|
||||
section below.
|
||||
You can convert a normal :class:`unittest.TestCase` to any of the subclasses:
|
||||
change the base class of your test from ``unittest.TestCase`` to the subclass.
|
||||
All of the standard Python unit test functionality will be available, and it
|
||||
will be augmented with some useful additions as described in each section
|
||||
below.
|
||||
|
||||
``SimpleTestCase``
|
||||
------------------
|
||||
|
@ -914,9 +914,9 @@ The live server listens on ``localhost`` and binds to port 0 which uses a free
|
|||
port assigned by the operating system. The server's URL can be accessed with
|
||||
``self.live_server_url`` during the tests.
|
||||
|
||||
To demonstrate how to use ``LiveServerTestCase``, let's write a simple Selenium
|
||||
test. First of all, you need to install the `selenium package`_ into your
|
||||
Python path:
|
||||
To demonstrate how to use ``LiveServerTestCase``, let's write a Selenium test.
|
||||
First of all, you need to install the `selenium package`_ into your Python
|
||||
path:
|
||||
|
||||
.. console::
|
||||
|
||||
|
@ -1002,10 +1002,10 @@ out the `full reference`_ for more details.
|
|||
|
||||
The tricky thing here is that there's really no such thing as a "page load,"
|
||||
especially in modern Web apps that generate HTML dynamically after the
|
||||
server generates the initial document. So, simply checking for the presence
|
||||
of ``<body>`` in the response might not necessarily be appropriate for all
|
||||
use cases. Please refer to the `Selenium FAQ`_ and
|
||||
`Selenium documentation`_ for more information.
|
||||
server generates the initial document. So, checking for the presence of
|
||||
``<body>`` in the response might not necessarily be appropriate for all use
|
||||
cases. Please refer to the `Selenium FAQ`_ and `Selenium documentation`_
|
||||
for more information.
|
||||
|
||||
.. _Selenium FAQ: https://web.archive.org/web/20160129132110/http://code.google.com/p/selenium/wiki/FrequentlyAskedQuestions#Q:_WebDriver_fails_to_find_elements_/_Does_not_block_on_page_loa
|
||||
.. _Selenium documentation: https://www.seleniumhq.org/docs/04_webdriver_advanced.html#explicit-waits
|
||||
|
@ -1039,7 +1039,7 @@ This means, instead of instantiating a ``Client`` in each test::
|
|||
response = client.get('/customer/index/')
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
...you can just refer to ``self.client``, like so::
|
||||
...you can refer to ``self.client``, like so::
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
@ -1268,9 +1268,9 @@ in the ``with`` block and reset its value to the previous state afterwards.
|
|||
.. method:: SimpleTestCase.modify_settings()
|
||||
|
||||
It can prove unwieldy to redefine settings that contain a list of values. In
|
||||
practice, adding or removing values is often sufficient. The
|
||||
:meth:`~django.test.SimpleTestCase.modify_settings` context manager makes it
|
||||
easy::
|
||||
practice, adding or removing values is often sufficient. Django provides the
|
||||
:meth:`~django.test.SimpleTestCase.modify_settings` context manager for easier
|
||||
settings changes::
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
|
@ -1806,12 +1806,12 @@ Django, such as your machine's mail server, if you're running one.)
|
|||
.. data:: django.core.mail.outbox
|
||||
|
||||
During test running, each outgoing email 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`` email 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.
|
||||
``django.core.mail.outbox``. This is a 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`` email 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::
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue