Removed use of non-standard indentation rules in docs, and the custom transform that supported them.

Doc writers should be aware that we are now back to normal ReST rules
regarding blockquotes.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16955 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Luke Plant 2011-10-10 17:32:33 +00:00
parent af244e47cc
commit c61987d75a
8 changed files with 777 additions and 797 deletions

View File

@ -62,7 +62,6 @@ def setup(app):
app.add_config_value('django_next_version', '0.0', True) app.add_config_value('django_next_version', '0.0', True)
app.add_directive('versionadded', VersionDirective) app.add_directive('versionadded', VersionDirective)
app.add_directive('versionchanged', VersionDirective) app.add_directive('versionchanged', VersionDirective)
app.add_transform(SuppressBlockquotes)
app.add_builder(DjangoStandaloneHTMLBuilder) app.add_builder(DjangoStandaloneHTMLBuilder)
@ -99,27 +98,6 @@ class VersionDirective(Directive):
return ret return ret
class SuppressBlockquotes(transforms.Transform):
"""
Remove the default blockquotes that encase indented list, tables, etc.
"""
default_priority = 300
suppress_blockquote_child_nodes = (
nodes.bullet_list,
nodes.enumerated_list,
nodes.definition_list,
nodes.literal_block,
nodes.doctest_block,
nodes.line_block,
nodes.table
)
def apply(self):
for node in self.document.traverse(nodes.block_quote):
if len(node.children) == 1 and isinstance(node.children[0], self.suppress_blockquote_child_nodes):
node.replace_self(node.children[0])
class DjangoHTMLTranslator(SmartyPantsHTMLTranslator): class DjangoHTMLTranslator(SmartyPantsHTMLTranslator):
""" """
Django-specific reST to HTML tweaks. Django-specific reST to HTML tweaks.

View File

@ -16,31 +16,31 @@ Overview
There are seven steps in activating the Django admin site: There are seven steps in activating the Django admin site:
1. Add ``'django.contrib.admin'`` to your :setting:`INSTALLED_APPS` 1. Add ``'django.contrib.admin'`` to your :setting:`INSTALLED_APPS`
setting. setting.
2. The admin has four dependencies - :mod:`django.contrib.auth`, 2. The admin has four dependencies - :mod:`django.contrib.auth`,
:mod:`django.contrib.contenttypes`, :mod:`django.contrib.contenttypes`,
:mod:`django.contrib.messages` and :mod:`django.contrib.messages` and
:mod:`django.contrib.sessions`. If these applications are not :mod:`django.contrib.sessions`. If these applications are not
in your :setting:`INSTALLED_APPS` list, add them. in your :setting:`INSTALLED_APPS` list, add them.
3. Add ``django.contrib.messages.context_processors.messages`` to 3. Add ``django.contrib.messages.context_processors.messages`` to
:setting:`TEMPLATE_CONTEXT_PROCESSORS` and :setting:`TEMPLATE_CONTEXT_PROCESSORS` and
:class:`~django.contrib.messages.middleware.MessageMiddleware` to :class:`~django.contrib.messages.middleware.MessageMiddleware` to
:setting:`MIDDLEWARE_CLASSES`. :setting:`MIDDLEWARE_CLASSES`.
4. Determine which of your application's models should be editable in the 4. Determine which of your application's models should be editable in the
admin interface. admin interface.
5. For each of those models, optionally create a ``ModelAdmin`` class that 5. For each of those models, optionally create a ``ModelAdmin`` class that
encapsulates the customized admin functionality and options for that encapsulates the customized admin functionality and options for that
particular model. particular model.
6. Instantiate an ``AdminSite`` and tell it about each of your models and 6. Instantiate an ``AdminSite`` and tell it about each of your models and
``ModelAdmin`` classes. ``ModelAdmin`` classes.
7. Hook the ``AdminSite`` instance into your URLconf. 7. Hook the ``AdminSite`` instance into your URLconf.
Other topics Other topics
------------ ------------
@ -239,54 +239,54 @@ subclass::
The ``field_options`` dictionary can have the following keys: The ``field_options`` dictionary can have the following keys:
* ``fields`` * ``fields``
A tuple of field names to display in this fieldset. This key is A tuple of field names to display in this fieldset. This key is
required. required.
Example:: Example::
{ {
'fields': ('first_name', 'last_name', 'address', 'city', 'state'), 'fields': ('first_name', 'last_name', 'address', 'city', 'state'),
} }
Just like with the :attr:`~ModelAdmin.fields` option, to display Just like with the :attr:`~ModelAdmin.fields` option, to display
multiple fields on the same line, wrap those fields in their own multiple fields on the same line, wrap those fields in their own
tuple. In this example, the ``first_name`` and ``last_name`` fields tuple. In this example, the ``first_name`` and ``last_name`` fields
will display on the same line:: will display on the same line::
{ {
'fields': (('first_name', 'last_name'), 'address', 'city', 'state'), 'fields': (('first_name', 'last_name'), 'address', 'city', 'state'),
} }
.. versionadded:: 1.2 .. versionadded:: 1.2
``fields`` can contain values defined in ``fields`` can contain values defined in
:attr:`~ModelAdmin.readonly_fields` to be displayed as read-only. :attr:`~ModelAdmin.readonly_fields` to be displayed as read-only.
* ``classes`` * ``classes``
A list containing extra CSS classes to apply to the fieldset. A list containing extra CSS classes to apply to the fieldset.
Example:: Example::
{ {
'classes': ['wide', 'extrapretty'], 'classes': ['wide', 'extrapretty'],
} }
Two useful classes defined by the default admin site stylesheet are Two useful classes defined by the default admin site stylesheet are
``collapse`` and ``wide``. Fieldsets with the ``collapse`` style ``collapse`` and ``wide``. Fieldsets with the ``collapse`` style
will be initially collapsed in the admin and replaced with a small will be initially collapsed in the admin and replaced with a small
"click to expand" link. Fieldsets with the ``wide`` style will be "click to expand" link. Fieldsets with the ``wide`` style will be
given extra horizontal space. given extra horizontal space.
* ``description`` * ``description``
A string of optional extra text to be displayed at the top of each A string of optional extra text to be displayed at the top of each
fieldset, under the heading of the fieldset. fieldset, under the heading of the fieldset.
Note that this value is *not* HTML-escaped when it's displayed in Note that this value is *not* HTML-escaped when it's displayed in
the admin interface. This lets you include HTML if you so desire. the admin interface. This lets you include HTML if you so desire.
Alternatively you can use plain text and Alternatively you can use plain text and
``django.utils.html.escape()`` to escape any HTML special ``django.utils.html.escape()`` to escape any HTML special
characters. characters.
.. attribute:: ModelAdmin.filter_horizontal .. attribute:: ModelAdmin.filter_horizontal
@ -400,129 +400,129 @@ subclass::
You have four possible values that can be used in ``list_display``: You have four possible values that can be used in ``list_display``:
* A field of the model. For example:: * A field of the model. For example::
class PersonAdmin(admin.ModelAdmin): class PersonAdmin(admin.ModelAdmin):
list_display = ('first_name', 'last_name') list_display = ('first_name', 'last_name')
* A callable that accepts one parameter for the model instance. For * A callable that accepts one parameter for the model instance. For
example:: example::
def upper_case_name(obj): def upper_case_name(obj):
return ("%s %s" % (obj.first_name, obj.last_name)).upper() return ("%s %s" % (obj.first_name, obj.last_name)).upper()
upper_case_name.short_description = 'Name'
class PersonAdmin(admin.ModelAdmin):
list_display = (upper_case_name,)
* A string representing an attribute on the ``ModelAdmin``. This
behaves same as the callable. For example::
class PersonAdmin(admin.ModelAdmin):
list_display = ('upper_case_name',)
def upper_case_name(self, obj):
return ("%s %s" % (obj.first_name, obj.last_name)).upper()
upper_case_name.short_description = 'Name' upper_case_name.short_description = 'Name'
class PersonAdmin(admin.ModelAdmin): * A string representing an attribute on the model. This behaves almost
list_display = (upper_case_name,) the same as the callable, but ``self`` in this context is the model
instance. Here's a full model example::
* A string representing an attribute on the ``ModelAdmin``. This class Person(models.Model):
behaves same as the callable. For example:: name = models.CharField(max_length=50)
birthday = models.DateField()
class PersonAdmin(admin.ModelAdmin): def decade_born_in(self):
list_display = ('upper_case_name',) return self.birthday.strftime('%Y')[:3] + "0's"
decade_born_in.short_description = 'Birth decade'
def upper_case_name(self, obj): class PersonAdmin(admin.ModelAdmin):
return ("%s %s" % (obj.first_name, obj.last_name)).upper() list_display = ('name', 'decade_born_in')
upper_case_name.short_description = 'Name'
* A string representing an attribute on the model. This behaves almost
the same as the callable, but ``self`` in this context is the model
instance. Here's a full model example::
class Person(models.Model):
name = models.CharField(max_length=50)
birthday = models.DateField()
def decade_born_in(self):
return self.birthday.strftime('%Y')[:3] + "0's"
decade_born_in.short_description = 'Birth decade'
class PersonAdmin(admin.ModelAdmin):
list_display = ('name', 'decade_born_in')
A few special cases to note about ``list_display``: A few special cases to note about ``list_display``:
* If the field is a ``ForeignKey``, Django will display the * If the field is a ``ForeignKey``, Django will display the
``__unicode__()`` of the related object. ``__unicode__()`` of the related object.
* ``ManyToManyField`` fields aren't supported, because that would * ``ManyToManyField`` fields aren't supported, because that would
entail executing a separate SQL statement for each row in the table. entail executing a separate SQL statement for each row in the table.
If you want to do this nonetheless, give your model a custom method, If you want to do this nonetheless, give your model a custom method,
and add that method's name to ``list_display``. (See below for more and add that method's name to ``list_display``. (See below for more
on custom methods in ``list_display``.) on custom methods in ``list_display``.)
* If the field is a ``BooleanField`` or ``NullBooleanField``, Django * If the field is a ``BooleanField`` or ``NullBooleanField``, Django
will display a pretty "on" or "off" icon instead of ``True`` or will display a pretty "on" or "off" icon instead of ``True`` or
``False``. ``False``.
* If the string given is a method of the model, ``ModelAdmin`` or a * If the string given is a method of the model, ``ModelAdmin`` or a
callable, Django will HTML-escape the output by default. If you'd callable, Django will HTML-escape the output by default. If you'd
rather not escape the output of the method, give the method an rather not escape the output of the method, give the method an
``allow_tags`` attribute whose value is ``True``. ``allow_tags`` attribute whose value is ``True``.
Here's a full example model:: Here's a full example model::
class Person(models.Model): class Person(models.Model):
first_name = models.CharField(max_length=50) first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50)
color_code = models.CharField(max_length=6) color_code = models.CharField(max_length=6)
def colored_name(self): def colored_name(self):
return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name) return '<span style="color: #%s;">%s %s</span>' % (self.color_code, self.first_name, self.last_name)
colored_name.allow_tags = True colored_name.allow_tags = True
class PersonAdmin(admin.ModelAdmin): class PersonAdmin(admin.ModelAdmin):
list_display = ('first_name', 'last_name', 'colored_name') list_display = ('first_name', 'last_name', 'colored_name')
* If the string given is a method of the model, ``ModelAdmin`` or a * If the string given is a method of the model, ``ModelAdmin`` or a
callable that returns True or False Django will display a pretty callable that returns True or False Django will display a pretty
"on" or "off" icon if you give the method a ``boolean`` attribute "on" or "off" icon if you give the method a ``boolean`` attribute
whose value is ``True``. whose value is ``True``.
Here's a full example model:: Here's a full example model::
class Person(models.Model): class Person(models.Model):
first_name = models.CharField(max_length=50) first_name = models.CharField(max_length=50)
birthday = models.DateField() birthday = models.DateField()
def born_in_fifties(self): def born_in_fifties(self):
return self.birthday.strftime('%Y')[:3] == '195' return self.birthday.strftime('%Y')[:3] == '195'
born_in_fifties.boolean = True born_in_fifties.boolean = True
class PersonAdmin(admin.ModelAdmin): class PersonAdmin(admin.ModelAdmin):
list_display = ('name', 'born_in_fifties') list_display = ('name', 'born_in_fifties')
* The ``__str__()`` and ``__unicode__()`` methods are just as valid in * The ``__str__()`` and ``__unicode__()`` methods are just as valid in
``list_display`` as any other model method, so it's perfectly OK to ``list_display`` as any other model method, so it's perfectly OK to
do this:: do this::
list_display = ('__unicode__', 'some_other_field') list_display = ('__unicode__', 'some_other_field')
* Usually, elements of ``list_display`` that aren't actual database * Usually, elements of ``list_display`` that aren't actual database
fields can't be used in sorting (because Django does all the sorting fields can't be used in sorting (because Django does all the sorting
at the database level). at the database level).
However, if an element of ``list_display`` represents a certain However, if an element of ``list_display`` represents a certain
database field, you can indicate this fact by setting the database field, you can indicate this fact by setting the
``admin_order_field`` attribute of the item. ``admin_order_field`` attribute of the item.
For example:: For example::
class Person(models.Model): class Person(models.Model):
first_name = models.CharField(max_length=50) first_name = models.CharField(max_length=50)
color_code = models.CharField(max_length=6) color_code = models.CharField(max_length=6)
def colored_first_name(self): def colored_first_name(self):
return '<span style="color: #%s;">%s</span>' % (self.color_code, self.first_name) return '<span style="color: #%s;">%s</span>' % (self.color_code, self.first_name)
colored_first_name.allow_tags = True colored_first_name.allow_tags = True
colored_first_name.admin_order_field = 'first_name' colored_first_name.admin_order_field = 'first_name'
class PersonAdmin(admin.ModelAdmin): class PersonAdmin(admin.ModelAdmin):
list_display = ('first_name', 'colored_first_name') list_display = ('first_name', 'colored_first_name')
The above will tell Django to order by the ``first_name`` field when The above will tell Django to order by the ``first_name`` field when
trying to sort by ``colored_first_name`` in the admin. trying to sort by ``colored_first_name`` in the admin.
.. attribute:: ModelAdmin.list_display_links .. attribute:: ModelAdmin.list_display_links
@ -561,12 +561,12 @@ subclass::
``list_editable`` interacts with a couple of other options in ``list_editable`` interacts with a couple of other options in
particular ways; you should note the following rules: particular ways; you should note the following rules:
* Any field in ``list_editable`` must also be in ``list_display``. * Any field in ``list_editable`` must also be in ``list_display``.
You can't edit a field that's not displayed! You can't edit a field that's not displayed!
* The same field can't be listed in both ``list_editable`` and * The same field can't be listed in both ``list_editable`` and
``list_display_links`` -- a field can't be both a form and ``list_display_links`` -- a field can't be both a form and
a link. a link.
You'll get a validation error if either of these rules are broken. You'll get a validation error if either of these rules are broken.
@ -582,119 +582,119 @@ subclass::
``list_filter`` should be a list of elements, where each element should be ``list_filter`` should be a list of elements, where each element should be
of one of the following types: of one of the following types:
* a field name, where the specified field should be either a * a field name, where the specified field should be either a
``BooleanField``, ``CharField``, ``DateField``, ``DateTimeField``, ``BooleanField``, ``CharField``, ``DateField``, ``DateTimeField``,
``IntegerField``, ``ForeignKey`` or ``ManyToManyField``, for example:: ``IntegerField``, ``ForeignKey`` or ``ManyToManyField``, for example::
class PersonAdmin(ModelAdmin): class PersonAdmin(ModelAdmin):
list_filter = ('is_staff', 'company') list_filter = ('is_staff', 'company')
.. versionadded:: 1.3 .. versionadded:: 1.3
Field names in ``list_filter`` can also span relations Field names in ``list_filter`` can also span relations
using the ``__`` lookup, for example:: using the ``__`` lookup, for example::
class PersonAdmin(UserAdmin): class PersonAdmin(UserAdmin):
list_filter = ('company__name',) list_filter = ('company__name',)
* a class inheriting from :mod:`django.contrib.admin.SimpleListFilter`, * a class inheriting from :mod:`django.contrib.admin.SimpleListFilter`,
which you need to provide the ``title`` and ``parameter_name`` which you need to provide the ``title`` and ``parameter_name``
attributes to and override the ``lookups`` and ``queryset`` methods, attributes to and override the ``lookups`` and ``queryset`` methods,
e.g.:: e.g.::
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter from django.contrib.admin import SimpleListFilter
class DecadeBornListFilter(SimpleListFilter): class DecadeBornListFilter(SimpleListFilter):
# Human-readable title which will be displayed in the # Human-readable title which will be displayed in the
# right admin sidebar just above the filter options. # right admin sidebar just above the filter options.
title = _('decade born') title = _('decade born')
# Parameter for the filter that will be used in the URL query. # Parameter for the filter that will be used in the URL query.
parameter_name = 'decade' parameter_name = 'decade'
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
""" """
Returns a list of tuples. The first element in each Returns a list of tuples. The first element in each
tuple is the coded value for the option that will tuple is the coded value for the option that will
appear in the URL query. The second element is the appear in the URL query. The second element is the
human-readable name for the option that will appear human-readable name for the option that will appear
in the right sidebar. in the right sidebar.
""" """
return ( return (
('80s', _('in the eighties')), ('80s', _('in the eighties')),
('90s', _('in the nineties')), ('90s', _('in the nineties')),
) )
def queryset(self, request, queryset): def queryset(self, request, queryset):
""" """
Returns the filtered queryset based on the value Returns the filtered queryset based on the value
provided in the query string and retrievable via provided in the query string and retrievable via
`self.value()`. `self.value()`.
""" """
# Compare the requested value (either '80s' or 'other') # Compare the requested value (either '80s' or 'other')
# to decide how to filter the queryset. # to decide how to filter the queryset.
if self.value() == '80s': if self.value() == '80s':
return queryset.filter(birthday__year__gte=1980, return queryset.filter(birthday__year__gte=1980,
birthday__year__lte=1989) birthday__year__lte=1989)
if self.value() == '90s': if self.value() == '90s':
return queryset.filter(birthday__year__gte=1990, return queryset.filter(birthday__year__gte=1990,
birthday__year__lte=1999) birthday__year__lte=1999)
class PersonAdmin(ModelAdmin): class PersonAdmin(ModelAdmin):
list_filter = (DecadeBornListFilter,) list_filter = (DecadeBornListFilter,)
.. note:: .. note::
As a convenience, the ``HttpRequest`` object is passed to the As a convenience, the ``HttpRequest`` object is passed to the
``lookups`` and ``queryset`` methods, for example:: ``lookups`` and ``queryset`` methods, for example::
class AuthDecadeBornListFilter(DecadeBornListFilter): class AuthDecadeBornListFilter(DecadeBornListFilter):
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
if request.user.is_superuser: if request.user.is_superuser:
return super(AuthDecadeBornListFilter, return super(AuthDecadeBornListFilter,
self).lookups(request, model_admin) self).lookups(request, model_admin)
def queryset(self, request, queryset): def queryset(self, request, queryset):
if request.user.is_superuser: if request.user.is_superuser:
return super(AuthDecadeBornListFilter, return super(AuthDecadeBornListFilter,
self).queryset(request, queryset) self).queryset(request, queryset)
Also as a convenience, the ``ModelAdmin`` object is passed to Also as a convenience, the ``ModelAdmin`` object is passed to
the ``lookups`` method, for example if you want to base the the ``lookups`` method, for example if you want to base the
lookups on the available data:: lookups on the available data::
class AdvancedDecadeBornListFilter(DecadeBornListFilter): class AdvancedDecadeBornListFilter(DecadeBornListFilter):
def lookups(self, request, model_admin): def lookups(self, request, model_admin):
""" """
Only show the lookups if there actually is Only show the lookups if there actually is
anyone born in the corresponding decades. anyone born in the corresponding decades.
""" """
qs = model_admin.queryset(request) qs = model_admin.queryset(request)
if qs.filter(birthday__year__gte=1980, if qs.filter(birthday__year__gte=1980,
birthday__year__lte=1989).exists(): birthday__year__lte=1989).exists():
yield ('80s', _('in the eighties')) yield ('80s', _('in the eighties'))
if qs.filter(birthday__year__gte=1990, if qs.filter(birthday__year__gte=1990,
birthday__year__lte=1999).exists(): birthday__year__lte=1999).exists():
yield ('90s', _('in the nineties')) yield ('90s', _('in the nineties'))
* a tuple, where the first element is a field name and the second * a tuple, where the first element is a field name and the second
element is a class inheriting from element is a class inheriting from
:mod:`django.contrib.admin.FieldListFilter`, for example:: :mod:`django.contrib.admin.FieldListFilter`, for example::
from django.contrib.admin import BooleanFieldListFilter from django.contrib.admin import BooleanFieldListFilter
class PersonAdmin(ModelAdmin): class PersonAdmin(ModelAdmin):
list_filter = ( list_filter = (
('is_staff', BooleanFieldListFilter), ('is_staff', BooleanFieldListFilter),
) )
.. note:: .. note::
The ``FieldListFilter`` API is currently considered internal The ``FieldListFilter`` API is currently considered internal
and prone to refactoring. and prone to refactoring.
.. attribute:: ModelAdmin.list_max_show_all .. attribute:: ModelAdmin.list_max_show_all
@ -1076,11 +1076,11 @@ templates used by the :class:`ModelAdmin` views:
However, the ``self.my_view`` function registered above suffers from two However, the ``self.my_view`` function registered above suffers from two
problems: problems:
* It will *not* perform any permission checks, so it will be accessible * It will *not* perform any permission checks, so it will be accessible
to the general public. to the general public.
* It will *not* provide any header details to prevent caching. This means * It will *not* provide any header details to prevent caching. This means
if the page retrieves data from the database, and caching middleware is if the page retrieves data from the database, and caching middleware is
active, the page could show outdated information. active, the page could show outdated information.
Since this is usually not what you want, Django provides a convenience Since this is usually not what you want, Django provides a convenience
wrapper to check permissions and mark the view as non-cacheable. This wrapper to check permissions and mark the view as non-cacheable. This
@ -1356,8 +1356,8 @@ information.
Django provides two subclasses of ``InlineModelAdmin`` and they are: Django provides two subclasses of ``InlineModelAdmin`` and they are:
* :class:`~django.contrib.admin.TabularInline` * :class:`~django.contrib.admin.TabularInline`
* :class:`~django.contrib.admin.StackedInline` * :class:`~django.contrib.admin.StackedInline`
The difference between these two is merely the template used to render The difference between these two is merely the template used to render
them. them.
@ -1735,11 +1735,11 @@ Templates which may be overridden per app or model
Not every template in ``contrib/admin/templates/admin`` may be overridden per Not every template in ``contrib/admin/templates/admin`` may be overridden per
app or per model. The following can: app or per model. The following can:
* ``app_index.html`` * ``app_index.html``
* ``change_form.html`` * ``change_form.html``
* ``change_list.html`` * ``change_list.html``
* ``delete_confirmation.html`` * ``delete_confirmation.html``
* ``object_history.html`` * ``object_history.html``
For those templates that cannot be overridden in this way, you may still For those templates that cannot be overridden in this way, you may still
override them for your entire project. Just place the new version in your override them for your entire project. Just place the new version in your
@ -1920,28 +1920,28 @@ accessible using Django's :ref:`URL reversing system <naming-url-patterns>`.
The :class:`AdminSite` provides the following named URL patterns: The :class:`AdminSite` provides the following named URL patterns:
====================== ======================== ============= ====================== ======================== =============
Page URL name Parameters Page URL name Parameters
====================== ======================== ============= ====================== ======================== =============
Index ``index`` Index ``index``
Logout ``logout`` Logout ``logout``
Password change ``password_change`` Password change ``password_change``
Password change done ``password_change_done`` Password change done ``password_change_done``
i18n javascript ``jsi18n`` i18n javascript ``jsi18n``
Application index page ``app_list`` ``app_label`` Application index page ``app_list`` ``app_label``
====================== ======================== ============= ====================== ======================== =============
Each :class:`ModelAdmin` instance provides an additional set of named URLs: Each :class:`ModelAdmin` instance provides an additional set of named URLs:
====================== =============================================== ============= ====================== =============================================== =============
Page URL name Parameters Page URL name Parameters
====================== =============================================== ============= ====================== =============================================== =============
Changelist ``{{ app_label }}_{{ model_name }}_changelist`` Changelist ``{{ app_label }}_{{ model_name }}_changelist``
Add ``{{ app_label }}_{{ model_name }}_add`` Add ``{{ app_label }}_{{ model_name }}_add``
History ``{{ app_label }}_{{ model_name }}_history`` ``object_id`` History ``{{ app_label }}_{{ model_name }}_history`` ``object_id``
Delete ``{{ app_label }}_{{ model_name }}_delete`` ``object_id`` Delete ``{{ app_label }}_{{ model_name }}_delete`` ``object_id``
Change ``{{ app_label }}_{{ model_name }}_change`` ``object_id`` Change ``{{ app_label }}_{{ model_name }}_change`` ``object_id``
====================== =============================================== ============= ====================== =============================================== =============
These named URLs are registered with the application namespace ``admin``, and These named URLs are registered with the application namespace ``admin``, and
with an instance namespace corresponding to the name of the Site instance. with an instance namespace corresponding to the name of the Site instance.

View File

@ -125,12 +125,12 @@ moderate comments"``) can approve and delete comments. This can also be
done through the ``admin`` as you'll see later. You might also want to done through the ``admin`` as you'll see later. You might also want to
customize the following templates: customize the following templates:
* ``flag.html`` * ``flag.html``
* ``flagged.html`` * ``flagged.html``
* ``approve.html`` * ``approve.html``
* ``approved.html`` * ``approved.html``
* ``delete.html`` * ``delete.html``
* ``deleted.html`` * ``deleted.html``
found under the directory structure we saw for ``form.html``. found under the directory structure we saw for ``form.html``.
@ -185,9 +185,9 @@ in-built with :doc:`generic comment moderation
</ref/contrib/comments/moderation>`. The comment moderation has the following </ref/contrib/comments/moderation>`. The comment moderation has the following
features (all of which or only certain can be enabled): features (all of which or only certain can be enabled):
* Enable comments for a particular model instance. * Enable comments for a particular model instance.
* Close comments after a particular (user-defined) number of days. * Close comments after a particular (user-defined) number of days.
* Email new comments to the site-staff. * Email new comments to the site-staff.
To enable comment moderation, we subclass the :class:`CommentModerator` and To enable comment moderation, we subclass the :class:`CommentModerator` and
register it with the moderation features we want. Let us suppose we want to register it with the moderation features we want. Let us suppose we want to

View File

@ -36,49 +36,49 @@ Supported countries
Countries currently supported by :mod:`~django.contrib.localflavor` are: Countries currently supported by :mod:`~django.contrib.localflavor` are:
* Argentina_ * Argentina_
* Australia_ * Australia_
* Austria_ * Austria_
* Belgium_ * Belgium_
* Brazil_ * Brazil_
* Canada_ * Canada_
* Chile_ * Chile_
* China_ * China_
* Colombia_ * Colombia_
* Croatia_ * Croatia_
* Czech_ * Czech_
* Ecuador_ * Ecuador_
* Finland_ * Finland_
* France_ * France_
* Germany_ * Germany_
* Iceland_ * Iceland_
* India_ * India_
* Indonesia_ * Indonesia_
* Ireland_ * Ireland_
* Israel_ * Israel_
* Italy_ * Italy_
* Japan_ * Japan_
* Kuwait_ * Kuwait_
* Macedonia_ * Macedonia_
* Mexico_ * Mexico_
* `The Netherlands`_ * `The Netherlands`_
* Norway_ * Norway_
* Peru_ * Peru_
* Poland_ * Poland_
* Portugal_ * Portugal_
* Paraguay_ * Paraguay_
* Romania_ * Romania_
* Russia_ * Russia_
* Slovakia_ * Slovakia_
* Slovenia_ * Slovenia_
* `South Africa`_ * `South Africa`_
* Spain_ * Spain_
* Sweden_ * Sweden_
* Switzerland_ * Switzerland_
* Turkey_ * Turkey_
* `United Kingdom`_ * `United Kingdom`_
* `United States of America`_ * `United States of America`_
* Uruguay_ * Uruguay_
The ``django.contrib.localflavor`` package also includes a ``generic`` subpackage, The ``django.contrib.localflavor`` package also includes a ``generic`` subpackage,
containing useful code that is not specific to one particular country or culture. containing useful code that is not specific to one particular country or culture.
@ -1286,13 +1286,13 @@ United States of America (``us``)
A form field that validates input as a U.S. Social Security Number (SSN). A form field that validates input as a U.S. Social Security Number (SSN).
A valid SSN must obey the following rules: A valid SSN must obey the following rules:
* Format of XXX-XX-XXXX * Format of XXX-XX-XXXX
* No group of digits consisting entirely of zeroes * No group of digits consisting entirely of zeroes
* Leading group of digits cannot be 666 * Leading group of digits cannot be 666
* Number not in promotional block 987-65-4320 through 987-65-4329 * Number not in promotional block 987-65-4320 through 987-65-4329
* Number not one known to be invalid due to widespread promotional * Number not one known to be invalid due to widespread promotional
use or distribution (e.g., the Woolworth's number or the 1962 use or distribution (e.g., the Woolworth's number or the 1962
promotional number) promotional number)
.. class:: us.forms.USStateField .. class:: us.forms.USStateField

View File

@ -24,57 +24,57 @@ actually occurs until you do something to evaluate the queryset.
You can evaluate a ``QuerySet`` in the following ways: You can evaluate a ``QuerySet`` in the following ways:
* **Iteration.** A ``QuerySet`` is iterable, and it executes its database * **Iteration.** A ``QuerySet`` is iterable, and it executes its database
query the first time you iterate over it. For example, this will print query the first time you iterate over it. For example, this will print
the headline of all entries in the database:: the headline of all entries in the database::
for e in Entry.objects.all(): for e in Entry.objects.all():
print e.headline print e.headline
* **Slicing.** As explained in :ref:`limiting-querysets`, a ``QuerySet`` can * **Slicing.** As explained in :ref:`limiting-querysets`, a ``QuerySet`` can
be sliced, using Python's array-slicing syntax. Usually slicing a be sliced, using Python's array-slicing syntax. Usually slicing a
``QuerySet`` returns another (unevaluated) ``QuerySet``, but Django will ``QuerySet`` returns another (unevaluated) ``QuerySet``, but Django will
execute the database query if you use the "step" parameter of slice execute the database query if you use the "step" parameter of slice
syntax. syntax.
* **Pickling/Caching.** See the following section for details of what * **Pickling/Caching.** See the following section for details of what
is involved when `pickling QuerySets`_. The important thing for the is involved when `pickling QuerySets`_. The important thing for the
purposes of this section is that the results are read from the database. purposes of this section is that the results are read from the database.
* **repr().** A ``QuerySet`` is evaluated when you call ``repr()`` on it. * **repr().** A ``QuerySet`` is evaluated when you call ``repr()`` on it.
This is for convenience in the Python interactive interpreter, so you can This is for convenience in the Python interactive interpreter, so you can
immediately see your results when using the API interactively. immediately see your results when using the API interactively.
* **len().** A ``QuerySet`` is evaluated when you call ``len()`` on it. * **len().** A ``QuerySet`` is evaluated when you call ``len()`` on it.
This, as you might expect, returns the length of the result list. This, as you might expect, returns the length of the result list.
Note: *Don't* use ``len()`` on ``QuerySet``\s if all you want to do is Note: *Don't* use ``len()`` on ``QuerySet``\s if all you want to do is
determine the number of records in the set. It's much more efficient to determine the number of records in the set. It's much more efficient to
handle a count at the database level, using SQL's ``SELECT COUNT(*)``, handle a count at the database level, using SQL's ``SELECT COUNT(*)``,
and Django provides a ``count()`` method for precisely this reason. See and Django provides a ``count()`` method for precisely this reason. See
``count()`` below. ``count()`` below.
* **list().** Force evaluation of a ``QuerySet`` by calling ``list()`` on * **list().** Force evaluation of a ``QuerySet`` by calling ``list()`` on
it. For example:: it. For example::
entry_list = list(Entry.objects.all()) entry_list = list(Entry.objects.all())
Be warned, though, that this could have a large memory overhead, because Be warned, though, that this could have a large memory overhead, because
Django will load each element of the list into memory. In contrast, Django will load each element of the list into memory. In contrast,
iterating over a ``QuerySet`` will take advantage of your database to iterating over a ``QuerySet`` will take advantage of your database to
load data and instantiate objects only as you need them. load data and instantiate objects only as you need them.
* **bool().** Testing a ``QuerySet`` in a boolean context, such as using * **bool().** Testing a ``QuerySet`` in a boolean context, such as using
``bool()``, ``or``, ``and`` or an ``if`` statement, will cause the query ``bool()``, ``or``, ``and`` or an ``if`` statement, will cause the query
to be executed. If there is at least one result, the ``QuerySet`` is to be executed. If there is at least one result, the ``QuerySet`` is
``True``, otherwise ``False``. For example:: ``True``, otherwise ``False``. For example::
if Entry.objects.filter(headline="Test"): if Entry.objects.filter(headline="Test"):
print "There is at least one Entry with the headline Test" print "There is at least one Entry with the headline Test"
Note: *Don't* use this if all you want to do is determine if at least one Note: *Don't* use this if all you want to do is determine if at least one
result exists, and don't need the actual objects. It's more efficient to result exists, and don't need the actual objects. It's more efficient to
use :meth:`exists() <QuerySet.exists>` (see below). use :meth:`exists() <QuerySet.exists>` (see below).
.. _pickling QuerySets: .. _pickling QuerySets:
@ -411,35 +411,35 @@ Example::
A few subtleties that are worth mentioning: A few subtleties that are worth mentioning:
* If you have a field called ``foo`` that is a * If you have a field called ``foo`` that is a
:class:`~django.db.models.ForeignKey`, the default ``values()`` call :class:`~django.db.models.ForeignKey`, the default ``values()`` call
will return a dictionary key called ``foo_id``, since this is the name will return a dictionary key called ``foo_id``, since this is the name
of the hidden model attribute that stores the actual value (the ``foo`` of the hidden model attribute that stores the actual value (the ``foo``
attribute refers to the related model). When you are calling attribute refers to the related model). When you are calling
``values()`` and passing in field names, you can pass in either ``foo`` ``values()`` and passing in field names, you can pass in either ``foo``
or ``foo_id`` and you will get back the same thing (the dictionary key or ``foo_id`` and you will get back the same thing (the dictionary key
will match the field name you passed in). will match the field name you passed in).
For example:: For example::
>>> Entry.objects.values() >>> Entry.objects.values()
[{'blog_id': 1, 'headline': u'First Entry', ...}, ...] [{'blog_id': 1, 'headline': u'First Entry', ...}, ...]
>>> Entry.objects.values('blog') >>> Entry.objects.values('blog')
[{'blog': 1}, ...] [{'blog': 1}, ...]
>>> Entry.objects.values('blog_id') >>> Entry.objects.values('blog_id')
[{'blog_id': 1}, ...] [{'blog_id': 1}, ...]
* When using ``values()`` together with :meth:`distinct()`, be aware that * When using ``values()`` together with :meth:`distinct()`, be aware that
ordering can affect the results. See the note in :meth:`distinct` for ordering can affect the results. See the note in :meth:`distinct` for
details. details.
* If you use a ``values()`` clause after an :meth:`extra()` call, * If you use a ``values()`` clause after an :meth:`extra()` call,
any fields defined by a ``select`` argument in the :meth:`extra()` must any fields defined by a ``select`` argument in the :meth:`extra()` must
be explicitly included in the ``values()`` call. Any :meth:`extra()` call be explicitly included in the ``values()`` call. Any :meth:`extra()` call
made after a ``values()`` call will have its extra selected fields made after a ``values()`` call will have its extra selected fields
ignored. ignored.
A ``ValuesQuerySet`` is useful when you know you're only going to need values A ``ValuesQuerySet`` is useful when you know you're only going to need values
from a small number of the available fields and you won't need the from a small number of the available fields and you won't need the
@ -524,11 +524,11 @@ model.
``datetime.datetime`` object in the result list is "truncated" to the given ``datetime.datetime`` object in the result list is "truncated" to the given
``type``. ``type``.
* ``"year"`` returns a list of all distinct year values for the field. * ``"year"`` returns a list of all distinct year values for the field.
* ``"month"`` returns a list of all distinct year/month values for the * ``"month"`` returns a list of all distinct year/month values for the
field. field.
* ``"day"`` returns a list of all distinct year/month/day values for the * ``"day"`` returns a list of all distinct year/month/day values for the
field. field.
``order``, which defaults to ``'ASC'``, should be either ``'ASC'`` or ``order``, which defaults to ``'ASC'``, should be either ``'ASC'`` or
``'DESC'``. This specifies how to order the results. ``'DESC'``. This specifies how to order the results.
@ -832,153 +832,155 @@ principle, so you should avoid them if possible.
Specify one or more of ``params``, ``select``, ``where`` or ``tables``. None Specify one or more of ``params``, ``select``, ``where`` or ``tables``. None
of the arguments is required, but you should use at least one of them. of the arguments is required, but you should use at least one of them.
* ``select`` * ``select``
The ``select`` argument lets you put extra fields in the ``SELECT``
clause. It should be a dictionary mapping attribute names to SQL
clauses to use to calculate that attribute.
Example:: The ``select`` argument lets you put extra fields in the ``SELECT``
clause. It should be a dictionary mapping attribute names to SQL
clauses to use to calculate that attribute.
Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"}) Example::
As a result, each ``Entry`` object will have an extra attribute, Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
``is_recent``, a boolean representing whether the entry's ``pub_date``
is greater than Jan. 1, 2006.
Django inserts the given SQL snippet directly into the ``SELECT`` As a result, each ``Entry`` object will have an extra attribute,
statement, so the resulting SQL of the above example would be something ``is_recent``, a boolean representing whether the entry's ``pub_date``
like:: is greater than Jan. 1, 2006.
SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent Django inserts the given SQL snippet directly into the ``SELECT``
FROM blog_entry; statement, so the resulting SQL of the above example would be something
like::
SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent
FROM blog_entry;
The next example is more advanced; it does a subquery to give each The next example is more advanced; it does a subquery to give each
resulting ``Blog`` object an ``entry_count`` attribute, an integer count resulting ``Blog`` object an ``entry_count`` attribute, an integer count
of associated ``Entry`` objects:: of associated ``Entry`` objects::
Blog.objects.extra( Blog.objects.extra(
select={ select={
'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id' 'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id'
}, },
) )
In this particular case, we're exploiting the fact that the query will In this particular case, we're exploiting the fact that the query will
already contain the ``blog_blog`` table in its ``FROM`` clause. already contain the ``blog_blog`` table in its ``FROM`` clause.
The resulting SQL of the above example would be:: The resulting SQL of the above example would be::
SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count
FROM blog_blog; FROM blog_blog;
Note that the parentheses required by most database engines around Note that the parentheses required by most database engines around
subqueries are not required in Django's ``select`` clauses. Also note subqueries are not required in Django's ``select`` clauses. Also note
that some database backends, such as some MySQL versions, don't support that some database backends, such as some MySQL versions, don't support
subqueries. subqueries.
In some rare cases, you might wish to pass parameters to the SQL In some rare cases, you might wish to pass parameters to the SQL
fragments in ``extra(select=...)``. For this purpose, use the fragments in ``extra(select=...)``. For this purpose, use the
``select_params`` parameter. Since ``select_params`` is a sequence and ``select_params`` parameter. Since ``select_params`` is a sequence and
the ``select`` attribute is a dictionary, some care is required so that the ``select`` attribute is a dictionary, some care is required so that
the parameters are matched up correctly with the extra select pieces. the parameters are matched up correctly with the extra select pieces.
In this situation, you should use a In this situation, you should use a
:class:`django.utils.datastructures.SortedDict` for the ``select`` :class:`django.utils.datastructures.SortedDict` for the ``select``
value, not just a normal Python dictionary. value, not just a normal Python dictionary.
This will work, for example:: This will work, for example::
Blog.objects.extra( Blog.objects.extra(
select=SortedDict([('a', '%s'), ('b', '%s')]), select=SortedDict([('a', '%s'), ('b', '%s')]),
select_params=('one', 'two')) select_params=('one', 'two'))
The only thing to be careful about when using select parameters in The only thing to be careful about when using select parameters in
``extra()`` is to avoid using the substring ``"%%s"`` (that's *two* ``extra()`` is to avoid using the substring ``"%%s"`` (that's *two*
percent characters before the ``s``) in the select strings. Django's percent characters before the ``s``) in the select strings. Django's
tracking of parameters looks for ``%s`` and an escaped ``%`` character tracking of parameters looks for ``%s`` and an escaped ``%`` character
like this isn't detected. That will lead to incorrect results. like this isn't detected. That will lead to incorrect results.
* ``where`` / ``tables`` * ``where`` / ``tables``
You can define explicit SQL ``WHERE`` clauses — perhaps to perform
non-explicit joins — by using ``where``. You can manually add tables to
the SQL ``FROM`` clause by using ``tables``.
``where`` and ``tables`` both take a list of strings. All ``where`` You can define explicit SQL ``WHERE`` clauses — perhaps to perform
parameters are "AND"ed to any other search criteria. non-explicit joins — by using ``where``. You can manually add tables to
the SQL ``FROM`` clause by using ``tables``.
Example:: ``where`` and ``tables`` both take a list of strings. All ``where``
parameters are "AND"ed to any other search criteria.
Entry.objects.extra(where=['id IN (3, 4, 5, 20)']) Example::
...translates (roughly) into the following SQL:: Entry.objects.extra(where=['id IN (3, 4, 5, 20)'])
SELECT * FROM blog_entry WHERE id IN (3, 4, 5, 20); ...translates (roughly) into the following SQL::
Be careful when using the ``tables`` parameter if you're specifying SELECT * FROM blog_entry WHERE id IN (3, 4, 5, 20);
tables that are already used in the query. When you add extra tables
via the ``tables`` parameter, Django assumes you want that table
included an extra time, if it is already included. That creates a
problem, since the table name will then be given an alias. If a table
appears multiple times in an SQL statement, the second and subsequent
occurrences must use aliases so the database can tell them apart. If
you're referring to the extra table you added in the extra ``where``
parameter this is going to cause errors.
Normally you'll only be adding extra tables that don't already appear Be careful when using the ``tables`` parameter if you're specifying
in the query. However, if the case outlined above does occur, there are tables that are already used in the query. When you add extra tables
a few solutions. First, see if you can get by without including the via the ``tables`` parameter, Django assumes you want that table
extra table and use the one already in the query. If that isn't included an extra time, if it is already included. That creates a
possible, put your ``extra()`` call at the front of the queryset problem, since the table name will then be given an alias. If a table
construction so that your table is the first use of that table. appears multiple times in an SQL statement, the second and subsequent
Finally, if all else fails, look at the query produced and rewrite your occurrences must use aliases so the database can tell them apart. If
``where`` addition to use the alias given to your extra table. The you're referring to the extra table you added in the extra ``where``
alias will be the same each time you construct the queryset in the same parameter this is going to cause errors.
way, so you can rely upon the alias name to not change.
* ``order_by`` Normally you'll only be adding extra tables that don't already appear
in the query. However, if the case outlined above does occur, there are
a few solutions. First, see if you can get by without including the
extra table and use the one already in the query. If that isn't
possible, put your ``extra()`` call at the front of the queryset
construction so that your table is the first use of that table.
Finally, if all else fails, look at the query produced and rewrite your
``where`` addition to use the alias given to your extra table. The
alias will be the same each time you construct the queryset in the same
way, so you can rely upon the alias name to not change.
If you need to order the resulting queryset using some of the new * ``order_by``
fields or tables you have included via ``extra()`` use the ``order_by``
parameter to ``extra()`` and pass in a sequence of strings. These
strings should either be model fields (as in the normal
:meth:`order_by()` method on querysets), of the form
``table_name.column_name`` or an alias for a column that you specified
in the ``select`` parameter to ``extra()``.
For example:: If you need to order the resulting queryset using some of the new
fields or tables you have included via ``extra()`` use the ``order_by``
parameter to ``extra()`` and pass in a sequence of strings. These
strings should either be model fields (as in the normal
:meth:`order_by()` method on querysets), of the form
``table_name.column_name`` or an alias for a column that you specified
in the ``select`` parameter to ``extra()``.
q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"}) For example::
q = q.extra(order_by = ['-is_recent'])
This would sort all the items for which ``is_recent`` is true to the q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
front of the result set (``True`` sorts before ``False`` in a q = q.extra(order_by = ['-is_recent'])
descending ordering).
This shows, by the way, that you can make multiple calls to ``extra()`` This would sort all the items for which ``is_recent`` is true to the
and it will behave as you expect (adding new constraints each time). front of the result set (``True`` sorts before ``False`` in a
descending ordering).
* ``params`` This shows, by the way, that you can make multiple calls to ``extra()``
and it will behave as you expect (adding new constraints each time).
The ``where`` parameter described above may use standard Python * ``params``
database string placeholders — ``'%s'`` to indicate parameters the
database engine should automatically quote. The ``params`` argument is
a list of any extra parameters to be substituted.
Example:: The ``where`` parameter described above may use standard Python
database string placeholders — ``'%s'`` to indicate parameters the
database engine should automatically quote. The ``params`` argument is
a list of any extra parameters to be substituted.
Entry.objects.extra(where=['headline=%s'], params=['Lennon']) Example::
Always use ``params`` instead of embedding values directly into Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
``where`` because ``params`` will ensure values are quoted correctly
according to your particular backend. For example, quotes will be
escaped correctly.
Bad:: Always use ``params`` instead of embedding values directly into
``where`` because ``params`` will ensure values are quoted correctly
according to your particular backend. For example, quotes will be
escaped correctly.
Entry.objects.extra(where=["headline='Lennon'"]) Bad::
Good:: Entry.objects.extra(where=["headline='Lennon'"])
Entry.objects.extra(where=['headline=%s'], params=['Lennon']) Good::
Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
defer defer
~~~~~ ~~~~~
@ -1304,11 +1306,11 @@ are)::
This has a number of caveats though: This has a number of caveats though:
* The model's ``save()`` method will not be called, and the ``pre_save`` and * The model's ``save()`` method will not be called, and the ``pre_save`` and
``post_save`` signals will not be sent. ``post_save`` signals will not be sent.
* It does not work with child models in a multi-table inheritance scenario. * It does not work with child models in a multi-table inheritance scenario.
* If the model's primary key is an :class:`~django.db.models.AutoField` it * If the model's primary key is an :class:`~django.db.models.AutoField` it
does not retrieve and set the primary key attribute, as ``save()`` does. does not retrieve and set the primary key attribute, as ``save()`` does.
count count
~~~~~ ~~~~~
@ -2059,8 +2061,8 @@ Avg
Returns the mean value of the given field. Returns the mean value of the given field.
* Default alias: ``<field>__avg`` * Default alias: ``<field>__avg``
* Return type: float * Return type: float
Count Count
~~~~~ ~~~~~
@ -2069,8 +2071,8 @@ Count
Returns the number of objects that are related through the provided field. Returns the number of objects that are related through the provided field.
* Default alias: ``<field>__count`` * Default alias: ``<field>__count``
* Return type: integer * Return type: integer
Has one optional argument: Has one optional argument:
@ -2086,8 +2088,8 @@ Max
Returns the maximum value of the given field. Returns the maximum value of the given field.
* Default alias: ``<field>__max`` * Default alias: ``<field>__max``
* Return type: same as input field * Return type: same as input field
Min Min
~~~ ~~~
@ -2096,8 +2098,8 @@ Min
Returns the minimum value of the given field. Returns the minimum value of the given field.
* Default alias: ``<field>__min`` * Default alias: ``<field>__min``
* Return type: same as input field * Return type: same as input field
StdDev StdDev
~~~~~~ ~~~~~~
@ -2106,8 +2108,8 @@ StdDev
Returns the standard deviation of the data in the provided field. Returns the standard deviation of the data in the provided field.
* Default alias: ``<field>__stddev`` * Default alias: ``<field>__stddev``
* Return type: float * Return type: float
Has one optional argument: Has one optional argument:
@ -2129,8 +2131,8 @@ Sum
Computes the sum of all values of the given field. Computes the sum of all values of the given field.
* Default alias: ``<field>__sum`` * Default alias: ``<field>__sum``
* Return type: same as input field * Return type: same as input field
Variance Variance
~~~~~~~~ ~~~~~~~~
@ -2139,8 +2141,8 @@ Variance
Returns the variance of the data in the provided field. Returns the variance of the data in the provided field.
* Default alias: ``<field>__variance`` * Default alias: ``<field>__variance``
* Return type: float * Return type: float
Has one optional argument: Has one optional argument:

View File

@ -240,7 +240,7 @@ Caveats with support of certain databases
Django attempts to support as many features as possible on all database Django attempts to support as many features as possible on all database
backends. However, not all database backends are alike, and in particular many of the supported database differ greatly from version to version. It's a good idea to checkout our :doc:`notes on supported database </ref/databases>`: backends. However, not all database backends are alike, and in particular many of the supported database differ greatly from version to version. It's a good idea to checkout our :doc:`notes on supported database </ref/databases>`:
- :ref:`mysql-notes` - :ref:`mysql-notes`
- :ref:`sqlite-notes` - :ref:`sqlite-notes`
- :ref:`oracle-notes` - :ref:`oracle-notes`

View File

@ -14,11 +14,11 @@ Overview
The auth system consists of: The auth system consists of:
* Users * Users
* Permissions: Binary (yes/no) flags designating whether a user may perform * Permissions: Binary (yes/no) flags designating whether a user may perform
a certain task. a certain task.
* Groups: A generic way of applying labels and permissions to more than one * Groups: A generic way of applying labels and permissions to more than one
user. user.
Installation Installation
============ ============
@ -26,11 +26,11 @@ Installation
Authentication support is bundled as a Django application in Authentication support is bundled as a Django application in
``django.contrib.auth``. To install it, do the following: ``django.contrib.auth``. To install it, do the following:
1. Put ``'django.contrib.auth'`` and ``'django.contrib.contenttypes'`` in 1. Put ``'django.contrib.auth'`` and ``'django.contrib.contenttypes'`` in
your :setting:`INSTALLED_APPS` setting. your :setting:`INSTALLED_APPS` setting.
(The :class:`~django.contrib.auth.models.Permission` model in (The :class:`~django.contrib.auth.models.Permission` model in
:mod:`django.contrib.auth` depends on :mod:`django.contrib.contenttypes`.) :mod:`django.contrib.auth` depends on :mod:`django.contrib.contenttypes`.)
2. Run the command ``manage.py syncdb``. 2. Run the command ``manage.py syncdb``.
Note that the default :file:`settings.py` file created by Note that the default :file:`settings.py` file created by
:djadmin:`django-admin.py startproject <startproject>` includes :djadmin:`django-admin.py startproject <startproject>` includes
@ -303,10 +303,10 @@ Manager functions
allowed characters. (Note that the default value of ``allowed_chars`` allowed characters. (Note that the default value of ``allowed_chars``
doesn't contain letters that can cause user confusion, including: doesn't contain letters that can cause user confusion, including:
* ``i``, ``l``, ``I``, and ``1`` (lowercase letter i, lowercase * ``i``, ``l``, ``I``, and ``1`` (lowercase letter i, lowercase
letter L, uppercase letter i, and the number one) letter L, uppercase letter i, and the number one)
* ``o``, ``O``, and ``0`` (uppercase letter o, lowercase letter o, * ``o``, ``O``, and ``0`` (uppercase letter o, lowercase letter o,
and zero) and zero)
Basic usage Basic usage
----------- -----------
@ -715,29 +715,29 @@ Sent when a user logs in successfully.
Arguments sent with this signal: Arguments sent with this signal:
``sender`` ``sender``
As above: the class of the user that just logged in. As above: the class of the user that just logged in.
``request`` ``request``
The current :class:`~django.http.HttpRequest` instance. The current :class:`~django.http.HttpRequest` instance.
``user`` ``user``
The user instance that just logged in. The user instance that just logged in.
.. data:: django.contrib.auth.signals.user_logged_out .. data:: django.contrib.auth.signals.user_logged_out
Sent when the logout method is called. Sent when the logout method is called.
``sender`` ``sender``
As above: the class of the user that just logged out or ``None`` As above: the class of the user that just logged out or ``None``
if the user was not authenticated. if the user was not authenticated.
``request`` ``request``
The current :class:`~django.http.HttpRequest` instance. The current :class:`~django.http.HttpRequest` instance.
``user`` ``user``
The user instance that just logged out or ``None`` if the The user instance that just logged out or ``None`` if the
user was not authenticated. user was not authenticated.
Limiting access to logged-in users Limiting access to logged-in users
---------------------------------- ----------------------------------
@ -830,38 +830,38 @@ The login_required decorator
Here's what ``django.contrib.auth.views.login`` does: Here's what ``django.contrib.auth.views.login`` does:
* If called via ``GET``, it displays a login form that POSTs to the * If called via ``GET``, it displays a login form that POSTs to the
same URL. More on this in a bit. same URL. More on this in a bit.
* If called via ``POST``, it tries to log the user in. If login is * If called via ``POST``, it tries to log the user in. If login is
successful, the view redirects to the URL specified in ``next``. If successful, the view redirects to the URL specified in ``next``. If
``next`` isn't provided, it redirects to ``next`` isn't provided, it redirects to
:setting:`settings.LOGIN_REDIRECT_URL <LOGIN_REDIRECT_URL>` (which :setting:`settings.LOGIN_REDIRECT_URL <LOGIN_REDIRECT_URL>` (which
defaults to ``/accounts/profile/``). If login isn't successful, it defaults to ``/accounts/profile/``). If login isn't successful, it
redisplays the login form. redisplays the login form.
It's your responsibility to provide the login form in a template called It's your responsibility to provide the login form in a template called
``registration/login.html`` by default. This template gets passed four ``registration/login.html`` by default. This template gets passed four
template context variables: template context variables:
* ``form``: A :class:`~django.forms.Form` object representing the login * ``form``: A :class:`~django.forms.Form` object representing the login
form. See the :doc:`forms documentation </topics/forms/index>` for form. See the :doc:`forms documentation </topics/forms/index>` for
more on ``Form`` objects. more on ``Form`` objects.
* ``next``: The URL to redirect to after successful login. This may * ``next``: The URL to redirect to after successful login. This may
contain a query string, too. contain a query string, too.
* ``site``: The current :class:`~django.contrib.sites.models.Site`, * ``site``: The current :class:`~django.contrib.sites.models.Site`,
according to the :setting:`SITE_ID` setting. If you don't have the according to the :setting:`SITE_ID` setting. If you don't have the
site framework installed, this will be set to an instance of site framework installed, this will be set to an instance of
:class:`~django.contrib.sites.models.RequestSite`, which derives the :class:`~django.contrib.sites.models.RequestSite`, which derives the
site name and domain from the current site name and domain from the current
:class:`~django.http.HttpRequest`. :class:`~django.http.HttpRequest`.
* ``site_name``: An alias for ``site.name``. If you don't have the site * ``site_name``: An alias for ``site.name``. If you don't have the site
framework installed, this will be set to the value of framework installed, this will be set to the value of
:attr:`request.META['SERVER_NAME'] <django.http.HttpRequest.META>`. :attr:`request.META['SERVER_NAME'] <django.http.HttpRequest.META>`.
For more on sites, see :doc:`/ref/contrib/sites`. For more on sites, see :doc:`/ref/contrib/sites`.
If you'd prefer not to call the template :file:`registration/login.html`, If you'd prefer not to call the template :file:`registration/login.html`,
you can pass the ``template_name`` parameter via the extra arguments to you can pass the ``template_name`` parameter via the extra arguments to
@ -950,31 +950,31 @@ includes a few other useful built-in views located in
**Optional arguments:** **Optional arguments:**
* ``next_page``: The URL to redirect to after logout. * ``next_page``: The URL to redirect to after logout.
* ``template_name``: The full name of a template to display after * ``template_name``: The full name of a template to display after
logging the user out. Defaults to logging the user out. Defaults to
:file:`registration/logged_out.html` if no argument is supplied. :file:`registration/logged_out.html` if no argument is supplied.
* ``redirect_field_name``: The name of a ``GET`` field containing the * ``redirect_field_name``: The name of a ``GET`` field containing the
URL to redirect to after log out. Overrides ``next_page`` if the given URL to redirect to after log out. Overrides ``next_page`` if the given
``GET`` parameter is passed. ``GET`` parameter is passed.
**Template context:** **Template context:**
* ``title``: The string "Logged out", localized. * ``title``: The string "Logged out", localized.
* ``site``: The current :class:`~django.contrib.sites.models.Site`, * ``site``: The current :class:`~django.contrib.sites.models.Site`,
according to the :setting:`SITE_ID` setting. If you don't have the according to the :setting:`SITE_ID` setting. If you don't have the
site framework installed, this will be set to an instance of site framework installed, this will be set to an instance of
:class:`~django.contrib.sites.models.RequestSite`, which derives the :class:`~django.contrib.sites.models.RequestSite`, which derives the
site name and domain from the current site name and domain from the current
:class:`~django.http.HttpRequest`. :class:`~django.http.HttpRequest`.
* ``site_name``: An alias for ``site.name``. If you don't have the site * ``site_name``: An alias for ``site.name``. If you don't have the site
framework installed, this will be set to the value of framework installed, this will be set to the value of
:attr:`request.META['SERVER_NAME'] <django.http.HttpRequest.META>`. :attr:`request.META['SERVER_NAME'] <django.http.HttpRequest.META>`.
For more on sites, see :doc:`/ref/contrib/sites`. For more on sites, see :doc:`/ref/contrib/sites`.
.. function:: logout_then_login(request[, login_url]) .. function:: logout_then_login(request[, login_url])
@ -984,8 +984,8 @@ includes a few other useful built-in views located in
**Optional arguments:** **Optional arguments:**
* ``login_url``: The URL of the login page to redirect to. * ``login_url``: The URL of the login page to redirect to.
Defaults to :setting:`settings.LOGIN_URL <LOGIN_URL>` if not supplied. Defaults to :setting:`settings.LOGIN_URL <LOGIN_URL>` if not supplied.
.. function:: password_change(request[, template_name, post_change_redirect, password_change_form]) .. function:: password_change(request[, template_name, post_change_redirect, password_change_form])
@ -995,23 +995,23 @@ includes a few other useful built-in views located in
**Optional arguments:** **Optional arguments:**
* ``template_name``: The full name of a template to use for * ``template_name``: The full name of a template to use for
displaying the password change form. Defaults to displaying the password change form. Defaults to
:file:`registration/password_change_form.html` if not supplied. :file:`registration/password_change_form.html` if not supplied.
* ``post_change_redirect``: The URL to redirect to after a successful * ``post_change_redirect``: The URL to redirect to after a successful
password change. password change.
.. versionadded:: 1.2 .. versionadded:: 1.2
* ``password_change_form``: A custom "change password" form which must * ``password_change_form``: A custom "change password" form which must
accept a ``user`` keyword argument. The form is responsible for accept a ``user`` keyword argument. The form is responsible for
actually changing the user's password. Defaults to actually changing the user's password. Defaults to
:class:`~django.contrib.auth.forms.PasswordChangeForm`. :class:`~django.contrib.auth.forms.PasswordChangeForm`.
**Template context:** **Template context:**
* ``form``: The password change form (see ``password_change_form`` above). * ``form``: The password change form (see ``password_change_form`` above).
.. function:: password_change_done(request[, template_name]) .. function:: password_change_done(request[, template_name])
@ -1021,9 +1021,9 @@ includes a few other useful built-in views located in
**Optional arguments:** **Optional arguments:**
* ``template_name``: The full name of a template to use. * ``template_name``: The full name of a template to use.
Defaults to :file:`registration/password_change_done.html` if not Defaults to :file:`registration/password_change_done.html` if not
supplied. supplied.
.. function:: password_reset(request[, is_admin_site, template_name, email_template_name, password_reset_form, token_generator, post_reset_redirect, from_email]) .. function:: password_reset(request[, is_admin_site, template_name, email_template_name, password_reset_form, token_generator, post_reset_redirect, from_email])
@ -1044,60 +1044,60 @@ includes a few other useful built-in views located in
**Optional arguments:** **Optional arguments:**
* ``template_name``: The full name of a template to use for * ``template_name``: The full name of a template to use for
displaying the password reset form. Defaults to displaying the password reset form. Defaults to
:file:`registration/password_reset_form.html` if not supplied. :file:`registration/password_reset_form.html` if not supplied.
* ``email_template_name``: The full name of a template to use for * ``email_template_name``: The full name of a template to use for
generating the email with the new password. Defaults to generating the email with the new password. Defaults to
:file:`registration/password_reset_email.html` if not supplied. :file:`registration/password_reset_email.html` if not supplied.
* ``subject_template_name``: The full name of a template to use for * ``subject_template_name``: The full name of a template to use for
the subject of the email with the new password. Defaults the subject of the email with the new password. Defaults
to :file:`registration/password_reset_subject.txt` if not supplied. to :file:`registration/password_reset_subject.txt` if not supplied.
.. versionadded:: 1.4 .. versionadded:: 1.4
* ``password_reset_form``: Form that will be used to set the password. * ``password_reset_form``: Form that will be used to set the password.
Defaults to :class:`~django.contrib.auth.forms.PasswordResetForm`. Defaults to :class:`~django.contrib.auth.forms.PasswordResetForm`.
* ``token_generator``: Instance of the class to check the password. This * ``token_generator``: Instance of the class to check the password. This
will default to ``default_token_generator``, it's an instance of will default to ``default_token_generator``, it's an instance of
``django.contrib.auth.tokens.PasswordResetTokenGenerator``. ``django.contrib.auth.tokens.PasswordResetTokenGenerator``.
* ``post_reset_redirect``: The URL to redirect to after a successful * ``post_reset_redirect``: The URL to redirect to after a successful
password change. password change.
* ``from_email``: A valid email address. By default Django uses * ``from_email``: A valid email address. By default Django uses
the :setting:`DEFAULT_FROM_EMAIL`. the :setting:`DEFAULT_FROM_EMAIL`.
**Template context:** **Template context:**
* ``form``: The form (see ``password_reset_form`` above) for resetting * ``form``: The form (see ``password_reset_form`` above) for resetting
the user's password. the user's password.
**Email template context:** **Email template context:**
* ``email``: An alias for ``user.email`` * ``email``: An alias for ``user.email``
* ``user``: The current :class:`~django.contrib.auth.models.User`, * ``user``: The current :class:`~django.contrib.auth.models.User`,
according to the ``email`` form field. Only active users are able to according to the ``email`` form field. Only active users are able to
reset their passwords (``User.is_active is True``). reset their passwords (``User.is_active is True``).
* ``site_name``: An alias for ``site.name``. If you don't have the site * ``site_name``: An alias for ``site.name``. If you don't have the site
framework installed, this will be set to the value of framework installed, this will be set to the value of
:attr:`request.META['SERVER_NAME'] <django.http.HttpRequest.META>`. :attr:`request.META['SERVER_NAME'] <django.http.HttpRequest.META>`.
For more on sites, see :doc:`/ref/contrib/sites`. For more on sites, see :doc:`/ref/contrib/sites`.
* ``domain``: An alias for ``site.domain``. If you don't have the site * ``domain``: An alias for ``site.domain``. If you don't have the site
framework installed, this will be set to the value of framework installed, this will be set to the value of
``request.get_host()``. ``request.get_host()``.
* ``protocol``: http or https * ``protocol``: http or https
* ``uid``: The user's id encoded in base 36. * ``uid``: The user's id encoded in base 36.
* ``token``: Token to check that the password is valid. * ``token``: Token to check that the password is valid.
Sample ``registration/password_reset_email.html`` (email body template): Sample ``registration/password_reset_email.html`` (email body template):
@ -1121,9 +1121,9 @@ includes a few other useful built-in views located in
**Optional arguments:** **Optional arguments:**
* ``template_name``: The full name of a template to use. * ``template_name``: The full name of a template to use.
Defaults to :file:`registration/password_reset_done.html` if not Defaults to :file:`registration/password_reset_done.html` if not
supplied. supplied.
.. function:: password_reset_confirm(request[, uidb36, token, template_name, token_generator, set_password_form, post_reset_redirect]) .. function:: password_reset_confirm(request[, uidb36, token, template_name, token_generator, set_password_form, post_reset_redirect])
@ -1133,31 +1133,31 @@ includes a few other useful built-in views located in
**Optional arguments:** **Optional arguments:**
* ``uidb36``: The user's id encoded in base 36. Defaults to ``None``. * ``uidb36``: The user's id encoded in base 36. Defaults to ``None``.
* ``token``: Token to check that the password is valid. Defaults to * ``token``: Token to check that the password is valid. Defaults to
``None``. ``None``.
* ``template_name``: The full name of a template to display the confirm * ``template_name``: The full name of a template to display the confirm
password view. Default value is :file:`registration/password_reset_confirm.html`. password view. Default value is :file:`registration/password_reset_confirm.html`.
* ``token_generator``: Instance of the class to check the password. This * ``token_generator``: Instance of the class to check the password. This
will default to ``default_token_generator``, it's an instance of will default to ``default_token_generator``, it's an instance of
``django.contrib.auth.tokens.PasswordResetTokenGenerator``. ``django.contrib.auth.tokens.PasswordResetTokenGenerator``.
* ``set_password_form``: Form that will be used to set the password. * ``set_password_form``: Form that will be used to set the password.
Defaults to :class:`~django.contrib.auth.forms.SetPasswordForm` Defaults to :class:`~django.contrib.auth.forms.SetPasswordForm`
* ``post_reset_redirect``: URL to redirect after the password reset * ``post_reset_redirect``: URL to redirect after the password reset
done. Defaults to ``None``. done. Defaults to ``None``.
**Template context:** **Template context:**
* ``form``: The form (see ``set_password_form`` above) for setting the * ``form``: The form (see ``set_password_form`` above) for setting the
new user's password. new user's password.
* ``validlink``: Boolean, True if the link (combination of uidb36 and * ``validlink``: Boolean, True if the link (combination of uidb36 and
token) is valid or unused yet. token) is valid or unused yet.
.. function:: password_reset_complete(request[,template_name]) .. function:: password_reset_complete(request[,template_name])
@ -1168,8 +1168,8 @@ includes a few other useful built-in views located in
**Optional arguments:** **Optional arguments:**
* ``template_name``: The full name of a template to display the view. * ``template_name``: The full name of a template to display the view.
Defaults to :file:`registration/password_reset_complete.html`. Defaults to :file:`registration/password_reset_complete.html`.
Helper functions Helper functions
---------------- ----------------
@ -1183,16 +1183,16 @@ Helper functions
**Required arguments:** **Required arguments:**
* ``next``: The URL to redirect to after a successful login. * ``next``: The URL to redirect to after a successful login.
**Optional arguments:** **Optional arguments:**
* ``login_url``: The URL of the login page to redirect to. * ``login_url``: The URL of the login page to redirect to.
Defaults to :setting:`settings.LOGIN_URL <LOGIN_URL>` if not supplied. Defaults to :setting:`settings.LOGIN_URL <LOGIN_URL>` if not supplied.
* ``redirect_field_name``: The name of a ``GET`` field containing the * ``redirect_field_name``: The name of a ``GET`` field containing the
URL to redirect to after log out. Overrides ``next`` if the given URL to redirect to after log out. Overrides ``next`` if the given
``GET`` parameter is passed. ``GET`` parameter is passed.
Built-in forms Built-in forms
-------------- --------------
@ -1354,13 +1354,13 @@ code.
The Django admin site uses permissions as follows: The Django admin site uses permissions as follows:
* Access to view the "add" form and add an object is limited to users with * Access to view the "add" form and add an object is limited to users with
the "add" permission for that type of object. the "add" permission for that type of object.
* Access to view the change list, view the "change" form and change an * Access to view the change list, view the "change" form and change an
object is limited to users with the "change" permission for that type of object is limited to users with the "change" permission for that type of
object. object.
* Access to delete an object is limited to users with the "delete" * Access to delete an object is limited to users with the "delete"
permission for that type of object. permission for that type of object.
Permissions are set globally per type of object, not per specific object Permissions are set globally per type of object, not per specific object
instance. For example, it's possible to say "Mary may change news stories," but instance. For example, it's possible to say "Mary may change news stories," but
@ -1389,9 +1389,9 @@ Assuming you have an application with an
:attr:`~django.db.models.Options.app_label` ``foo`` and a model named ``Bar``, :attr:`~django.db.models.Options.app_label` ``foo`` and a model named ``Bar``,
to test for basic permissions you should use: to test for basic permissions you should use:
* add: ``user.has_perm('foo.add_bar')`` * add: ``user.has_perm('foo.add_bar')``
* change: ``user.has_perm('foo.change_bar')`` * change: ``user.has_perm('foo.change_bar')``
* delete: ``user.has_perm('foo.delete_bar')`` * delete: ``user.has_perm('foo.delete_bar')``
.. _custom-permissions: .. _custom-permissions:

View File

@ -92,10 +92,10 @@ Use a dot (``.``) to access attributes of a variable.
Technically, when the template system encounters a dot, it tries the Technically, when the template system encounters a dot, it tries the
following lookups, in this order: following lookups, in this order:
* Dictionary lookup * Dictionary lookup
* Attribute lookup * Attribute lookup
* Method call * Method call
* List-index lookup * List-index lookup
In the above example, ``{{ section.title }}`` will be replaced with the In the above example, ``{{ section.title }}`` will be replaced with the
``title`` attribute of the ``section`` object. ``title`` attribute of the ``section`` object.
@ -129,32 +129,32 @@ them in the :ref:`built-in filter reference <ref-templates-builtins-filters>`.
To give you a taste of what's available, here are some of the more commonly To give you a taste of what's available, here are some of the more commonly
used template filters: used template filters:
:tfilter:`default` :tfilter:`default`
If a variable is false or empty, use given default. Otherwise, use the If a variable is false or empty, use given default. Otherwise, use the
value of the variable value of the variable
For example:: For example::
{{ value|default:"nothing" }} {{ value|default:"nothing" }}
If ``value`` isn't provided or is empty, the above will display If ``value`` isn't provided or is empty, the above will display
"``nothing``". "``nothing``".
:tfilter:`length` :tfilter:`length`
Returns the length of the value. This works for both strings and lists; Returns the length of the value. This works for both strings and lists;
for example:: for example::
{{ value|length }} {{ value|length }}
If ``value`` is ``['a', 'b', 'c', 'd']``, the output will be ``4``. If ``value`` is ``['a', 'b', 'c', 'd']``, the output will be ``4``.
:tfilter:`striptags` :tfilter:`striptags`
Strips all [X]HTML tags. For example:: Strips all [X]HTML tags. For example::
{{ value|striptags }} {{ value|striptags }}
If ``value`` is ``"<b>Joel</b> <button>is</button> a If ``value`` is ``"<b>Joel</b> <button>is</button> a
<span>slug</span>"``, the output will be ``"Joel is a slug"``. <span>slug</span>"``, the output will be ``"Joel is a slug"``.
Again, these are just a few examples; see the :ref:`built-in filter reference Again, these are just a few examples; see the :ref:`built-in filter reference
<ref-templates-builtins-filters>` for the complete list. <ref-templates-builtins-filters>` for the complete list.
@ -183,40 +183,40 @@ them in the :ref:`built-in tag reference <ref-templates-builtins-tags>`. To give
you a taste of what's available, here are some of the more commonly used you a taste of what's available, here are some of the more commonly used
tags: tags:
:ttag:`for` :ttag:`for`
Loop over each item in an array. For example, to display a list of athletes Loop over each item in an array. For example, to display a list of athletes
provided in ``athlete_list``:: provided in ``athlete_list``::
<ul> <ul>
{% for athlete in athlete_list %} {% for athlete in athlete_list %}
<li>{{ athlete.name }}</li> <li>{{ athlete.name }}</li>
{% endfor %} {% endfor %}
</ul> </ul>
:ttag:`if` and ``else`` :ttag:`if` and ``else``
Evaluates a variable, and if that variable is "true" the contents of the Evaluates a variable, and if that variable is "true" the contents of the
block are displayed:: block are displayed::
{% if athlete_list %} {% if athlete_list %}
Number of athletes: {{ athlete_list|length }} Number of athletes: {{ athlete_list|length }}
{% else %} {% else %}
No athletes. No athletes.
{% endif %} {% endif %}
In the above, if ``athlete_list`` is not empty, the number of athletes In the above, if ``athlete_list`` is not empty, the number of athletes
will be displayed by the ``{{ athlete_list|length }}`` variable. will be displayed by the ``{{ athlete_list|length }}`` variable.
You can also use filters and various operators in the :ttag:`if` tag:: You can also use filters and various operators in the :ttag:`if` tag::
{% if athlete_list|length > 1 %} {% if athlete_list|length > 1 %}
Team: {% for athlete in athlete_list %} ... {% endfor %} Team: {% for athlete in athlete_list %} ... {% endfor %}
{% else %} {% else %}
Athlete: {{ athlete_list.0.name }} Athlete: {{ athlete_list.0.name }}
{% endif %} {% endif %}
:ttag:`block` and :ttag:`extends` :ttag:`block` and :ttag:`extends`
Set up `template inheritance`_ (see below), a powerful way Set up `template inheritance`_ (see below), a powerful way
of cutting down on "boilerplate" in templates. of cutting down on "boilerplate" in templates.
Again, the above is only a selection of the whole list; see the :ref:`built-in Again, the above is only a selection of the whole list; see the :ref:`built-in
tag reference <ref-templates-builtins-tags>` for the complete list. tag reference <ref-templates-builtins-tags>` for the complete list.
@ -344,49 +344,49 @@ tag in a parent template is always used as a fallback.
You can use as many levels of inheritance as needed. One common way of using You can use as many levels of inheritance as needed. One common way of using
inheritance is the following three-level approach: inheritance is the following three-level approach:
* Create a ``base.html`` template that holds the main look-and-feel of your * Create a ``base.html`` template that holds the main look-and-feel of your
site. site.
* Create a ``base_SECTIONNAME.html`` template for each "section" of your * Create a ``base_SECTIONNAME.html`` template for each "section" of your
site. For example, ``base_news.html``, ``base_sports.html``. These site. For example, ``base_news.html``, ``base_sports.html``. These
templates all extend ``base.html`` and include section-specific templates all extend ``base.html`` and include section-specific
styles/design. styles/design.
* Create individual templates for each type of page, such as a news * Create individual templates for each type of page, such as a news
article or blog entry. These templates extend the appropriate section article or blog entry. These templates extend the appropriate section
template. template.
This approach maximizes code reuse and makes it easy to add items to shared This approach maximizes code reuse and makes it easy to add items to shared
content areas, such as section-wide navigation. content areas, such as section-wide navigation.
Here are some tips for working with inheritance: Here are some tips for working with inheritance:
* If you use :ttag:`{% extends %}<extends>` in a template, it must be the first template * If you use :ttag:`{% extends %}<extends>` in a template, it must be the first template
tag in that template. Template inheritance won't work, otherwise. tag in that template. Template inheritance won't work, otherwise.
* More :ttag:`{% block %}<block>` tags in your base templates are better. Remember, * More :ttag:`{% block %}<block>` tags in your base templates are better. Remember,
child templates don't have to define all parent blocks, so you can fill child templates don't have to define all parent blocks, so you can fill
in reasonable defaults in a number of blocks, then only define the ones in reasonable defaults in a number of blocks, then only define the ones
you need later. It's better to have more hooks than fewer hooks. you need later. It's better to have more hooks than fewer hooks.
* If you find yourself duplicating content in a number of templates, it * If you find yourself duplicating content in a number of templates, it
probably means you should move that content to a ``{% block %}`` in a probably means you should move that content to a ``{% block %}`` in a
parent template. parent template.
* If you need to get the content of the block from the parent template, * If you need to get the content of the block from the parent template,
the ``{{ block.super }}`` variable will do the trick. This is useful the ``{{ block.super }}`` variable will do the trick. This is useful
if you want to add to the contents of a parent block instead of if you want to add to the contents of a parent block instead of
completely overriding it. Data inserted using ``{{ block.super }}`` will completely overriding it. Data inserted using ``{{ block.super }}`` will
not be automatically escaped (see the `next section`_), since it was not be automatically escaped (see the `next section`_), since it was
already escaped, if necessary, in the parent template. already escaped, if necessary, in the parent template.
* For extra readability, you can optionally give a *name* to your * For extra readability, you can optionally give a *name* to your
``{% endblock %}`` tag. For example:: ``{% endblock %}`` tag. For example::
{% block content %} {% block content %}
... ...
{% endblock content %} {% endblock content %}
In larger templates, this technique helps you see which ``{% block %}`` In larger templates, this technique helps you see which ``{% block %}``
tags are being closed. tags are being closed.
Finally, note that you can't define multiple :ttag:`block` tags with the same Finally, note that you can't define multiple :ttag:`block` tags with the same
name in the same template. This limitation exists because a block tag works in name in the same template. This limitation exists because a block tag works in
@ -437,25 +437,25 @@ do potentially bad things. This type of security exploit is called a
To avoid this problem, you have two options: To avoid this problem, you have two options:
* One, you can make sure to run each untrusted variable through the * One, you can make sure to run each untrusted variable through the
:tfilter:`escape` filter (documented below), which converts potentially :tfilter:`escape` filter (documented below), which converts potentially
harmful HTML characters to unharmful ones. This was the default solution harmful HTML characters to unharmful ones. This was the default solution
in Django for its first few years, but the problem is that it puts the in Django for its first few years, but the problem is that it puts the
onus on *you*, the developer / template author, to ensure you're escaping onus on *you*, the developer / template author, to ensure you're escaping
everything. It's easy to forget to escape data. everything. It's easy to forget to escape data.
* Two, you can take advantage of Django's automatic HTML escaping. The * Two, you can take advantage of Django's automatic HTML escaping. The
remainder of this section describes how auto-escaping works. remainder of this section describes how auto-escaping works.
By default in Django, every template automatically escapes the output By default in Django, every template automatically escapes the output
of every variable tag. Specifically, these five characters are of every variable tag. Specifically, these five characters are
escaped: escaped:
* ``<`` is converted to ``&lt;`` * ``<`` is converted to ``&lt;``
* ``>`` is converted to ``&gt;`` * ``>`` is converted to ``&gt;``
* ``'`` (single quote) is converted to ``&#39;`` * ``'`` (single quote) is converted to ``&#39;``
* ``"`` (double quote) is converted to ``&quot;`` * ``"`` (double quote) is converted to ``&quot;``
* ``&`` is converted to ``&amp;`` * ``&`` is converted to ``&amp;``
Again, we stress that this behavior is on by default. If you're using Django's Again, we stress that this behavior is on by default. If you're using Django's
template system, you're protected. template system, you're protected.