Fixed #15057 - documented change in [14992]

Thanks to Tai Lee for the patch.

Refs #15025, #7153

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15188 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Luke Plant 2011-01-13 13:47:21 +00:00
parent 80f4826063
commit 7b8c38250c
3 changed files with 50 additions and 29 deletions

View File

@ -415,9 +415,9 @@ like:
The template system uses dot-lookup syntax to access variable attributes. In
the example of ``{{ poll.question }}``, first Django does a dictionary lookup
on the object ``poll``. Failing that, it tries attribute lookup -- which works,
in this case. If attribute lookup had failed, it would've tried calling the
method ``question()`` on the poll object.
on the object ``poll``. Failing that, it tries an attribute lookup -- which
works, in this case. If attribute lookup had failed, it would've tried a
list-index lookup.
Method-calling happens in the ``{% for %}`` loop: ``poll.choice_set.all`` is
interpreted as the Python code ``poll.choice_set.all()``, which returns an

View File

@ -115,18 +115,15 @@ Variable names must consist of any letter (A-Z), any digit (0-9), an underscore
or a dot.
Dots have a special meaning in template rendering. A dot in a variable name
signifies **lookup**. Specifically, when the template system encounters a dot
in a variable name, it tries the following lookups, in this order:
signifies a **lookup**. Specifically, when the template system encounters a
dot in a variable name, it tries the following lookups, in this order:
* Dictionary lookup. Example: ``foo["bar"]``
* Attribute lookup. Example: ``foo.bar``
* Method call. Example: ``foo.bar()``
* List-index lookup. Example: ``foo[bar]``
The template system uses the first lookup type that works. It's short-circuit
logic.
Here are a few examples::
logic. Here are a few examples::
>>> from django.template import Context, Template
>>> t = Template("My name is {{ person.first_name }}.")
@ -141,26 +138,34 @@ Here are a few examples::
>>> t.render(Context({"person": p}))
"My name is Ron."
>>> class PersonClass2:
... def first_name(self):
... return "Samantha"
>>> p = PersonClass2()
>>> t.render(Context({"person": p}))
"My name is Samantha."
>>> t = Template("The first stooge in the list is {{ stooges.0 }}.")
>>> c = Context({"stooges": ["Larry", "Curly", "Moe"]})
>>> t.render(c)
"The first stooge in the list is Larry."
Method lookups are slightly more complex than the other lookup types. Here are
some things to keep in mind:
If any part of the variable is callable, the template system will try calling
it. Example::
* If, during the method lookup, a method raises an exception, the exception
will be propagated, unless the exception has an attribute
>>> class PersonClass2:
... def name(self):
... return "Samantha"
>>> t = Template("My name is {{ person.name }}.")
>>> t.render(Context({"person": PersonClass2}))
"My name is Samantha."
.. versionchanged:: 1.3
Previously, only variables that originated with an attribute lookup would
be called by the template system. This change was made for consistency
across lookup types.
Callable variables are slightly more complex than variables which only require
straight lookups. Here are some things to keep in mind:
* If the variable raises an exception when called, the exception will be
propagated, unless the exception has an attribute
``silent_variable_failure`` whose value is ``True``. If the exception
*does* have a ``silent_variable_failure`` attribute, the variable will
render as an empty string. Example::
*does* have a ``silent_variable_failure`` attribute whose value is
``True``, the variable will render as an empty string. Example::
>>> t = Template("My name is {{ person.first_name }}.")
>>> class PersonClass3:
@ -187,12 +192,12 @@ some things to keep in mind:
with Django model objects, any ``DoesNotExist`` exception will fail
silently.
* A method call will only work if the method has no required arguments.
Otherwise, the system will move to the next lookup type (list-index
lookup).
* A variable can only be called if it has no required arguments. Otherwise,
the system will return an empty string.
* Obviously, some methods have side effects, and it'd be either foolish or
a security hole to allow the template system to access them.
* Obviously, there can be side effects when calling some variables, and
it'd be either foolish or a security hole to allow the template system
to access them.
A good example is the :meth:`~django.db.models.Model.delete` method on
each Django model object. The template system shouldn't be allowed to do
@ -200,8 +205,8 @@ some things to keep in mind:
I will now delete this valuable data. {{ data.delete }}
To prevent this, set a function attribute ``alters_data`` on the method.
The template system won't execute a method if the method has
To prevent this, set an ``alters_data`` attribute on the callable
variable. The template system won't call a variable if it has
``alters_data=True`` set. The dynamically-generated
:meth:`~django.db.models.Model.delete` and
:meth:`~django.db.models.Model.save` methods on Django model objects get

View File

@ -392,7 +392,23 @@ if you need to instantiate an empty ``FormSet``, don't pass in the data or use
>>> formset = ArticleFormSet()
>>> formset = ArticleFormSet(data=None)
Callables in templates
~~~~~~~~~~~~~~~~~~~~~~
Previously, a callable in a template would only be called automatically as part
of the variable resolution process if it was retrieved via attribute
lookup. This was an inconsistency that could result in confusing and unhelpful
behaviour::
>>> Template("{{ user.get_full_name }}").render(Context({'user': user}))
u'Joe Bloggs'
>>> Template("{{ full_name }}").render(Context({'full_name': user.get_full_name}))
u'<bound method User.get_full_name of <...
This has been resolved in Django 1.3 - the result in both cases will be ``u'Joe
Bloggs'``. Although the previous behaviour was not useful for a template language
designed for web designers, and was never deliberately supported, it is possible
that some templates may be broken by this change.
.. _deprecated-features-1.3: