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 template system uses dot-lookup syntax to access variable attributes. In
the example of ``{{ poll.question }}``, first Django does a dictionary lookup the example of ``{{ poll.question }}``, first Django does a dictionary lookup
on the object ``poll``. Failing that, it tries attribute lookup -- which works, on the object ``poll``. Failing that, it tries an attribute lookup -- which
in this case. If attribute lookup had failed, it would've tried calling the works, in this case. If attribute lookup had failed, it would've tried a
method ``question()`` on the poll object. list-index lookup.
Method-calling happens in the ``{% for %}`` loop: ``poll.choice_set.all`` is Method-calling happens in the ``{% for %}`` loop: ``poll.choice_set.all`` is
interpreted as the Python code ``poll.choice_set.all()``, which returns an 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. or a dot.
Dots have a special meaning in template rendering. A dot in a variable name Dots have a special meaning in template rendering. A dot in a variable name
signifies **lookup**. Specifically, when the template system encounters a dot signifies a **lookup**. Specifically, when the template system encounters a
in a variable name, it tries the following lookups, in this order: dot in a variable name, it tries the following lookups, in this order:
* Dictionary lookup. Example: ``foo["bar"]`` * Dictionary lookup. Example: ``foo["bar"]``
* Attribute lookup. Example: ``foo.bar`` * Attribute lookup. Example: ``foo.bar``
* Method call. Example: ``foo.bar()``
* List-index lookup. Example: ``foo[bar]`` * List-index lookup. Example: ``foo[bar]``
The template system uses the first lookup type that works. It's short-circuit The template system uses the first lookup type that works. It's short-circuit
logic. logic. Here are a few examples::
Here are a few examples::
>>> from django.template import Context, Template >>> from django.template import Context, Template
>>> t = Template("My name is {{ person.first_name }}.") >>> t = Template("My name is {{ person.first_name }}.")
@ -141,26 +138,34 @@ Here are a few examples::
>>> t.render(Context({"person": p})) >>> t.render(Context({"person": p}))
"My name is Ron." "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 }}.") >>> t = Template("The first stooge in the list is {{ stooges.0 }}.")
>>> c = Context({"stooges": ["Larry", "Curly", "Moe"]}) >>> c = Context({"stooges": ["Larry", "Curly", "Moe"]})
>>> t.render(c) >>> t.render(c)
"The first stooge in the list is Larry." "The first stooge in the list is Larry."
Method lookups are slightly more complex than the other lookup types. Here are If any part of the variable is callable, the template system will try calling
some things to keep in mind: it. Example::
* If, during the method lookup, a method raises an exception, the exception >>> class PersonClass2:
will be propagated, unless the exception has an attribute ... 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 ``silent_variable_failure`` whose value is ``True``. If the exception
*does* have a ``silent_variable_failure`` attribute, the variable will *does* have a ``silent_variable_failure`` attribute whose value is
render as an empty string. Example:: ``True``, the variable will render as an empty string. Example::
>>> t = Template("My name is {{ person.first_name }}.") >>> t = Template("My name is {{ person.first_name }}.")
>>> class PersonClass3: >>> class PersonClass3:
@ -187,12 +192,12 @@ some things to keep in mind:
with Django model objects, any ``DoesNotExist`` exception will fail with Django model objects, any ``DoesNotExist`` exception will fail
silently. silently.
* A method call will only work if the method has no required arguments. * A variable can only be called if it has no required arguments. Otherwise,
Otherwise, the system will move to the next lookup type (list-index the system will return an empty string.
lookup).
* Obviously, some methods have side effects, and it'd be either foolish or * Obviously, there can be side effects when calling some variables, and
a security hole to allow the template system to access them. 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 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 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 }} I will now delete this valuable data. {{ data.delete }}
To prevent this, set a function attribute ``alters_data`` on the method. To prevent this, set an ``alters_data`` attribute on the callable
The template system won't execute a method if the method has variable. The template system won't call a variable if it has
``alters_data=True`` set. The dynamically-generated ``alters_data=True`` set. The dynamically-generated
:meth:`~django.db.models.Model.delete` and :meth:`~django.db.models.Model.delete` and
:meth:`~django.db.models.Model.save` methods on Django model objects get :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()
>>> formset = ArticleFormSet(data=None) >>> 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: .. _deprecated-features-1.3: