diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
index 1b07413..9be64f0 100644
a
|
b
|
class WidthRatioNode(Node):
|
417 | 417 | return str(int(round(ratio))) |
418 | 418 | |
419 | 419 | class WithNode(Node): |
420 | | def __init__(self, var, name, nodelist): |
421 | | self.var = var |
422 | | self.name = name |
| 420 | def __init__(self, names, vars, nodelist): |
| 421 | self.names = names |
| 422 | self.vars = vars |
423 | 423 | self.nodelist = nodelist |
424 | 424 | |
425 | 425 | def __repr__(self): |
426 | 426 | return "<WithNode>" |
427 | 427 | |
428 | 428 | def render(self, context): |
429 | | val = self.var.resolve(context) |
| 429 | values = [var.resolve(context) for var in self.vars] |
430 | 430 | context.push() |
431 | | context[self.name] = val |
| 431 | for name, value in zip(self.names, values): |
| 432 | context[name] = value |
432 | 433 | output = self.nodelist.render(context) |
433 | 434 | context.pop() |
434 | 435 | return output |
… |
… |
widthratio = register.tag(widthratio)
|
1198 | 1199 | def do_with(parser, token): |
1199 | 1200 | """ |
1200 | 1201 | Adds a value to the context (inside of this block) for caching and easy |
1201 | | access. |
| 1202 | access. You can bind a value to a new name using ``as``. You can chain |
| 1203 | multiple bindings with ``and``. You can also safely swap variables. |
1202 | 1204 | |
1203 | 1205 | For example:: |
1204 | 1206 | |
1205 | 1207 | {% with person.some_sql_method as total %} |
1206 | 1208 | {{ total }} object{{ total|pluralize }} |
1207 | 1209 | {% endwith %} |
| 1210 | |
| 1211 | {% with x|add:5 as y and y as x %} |
| 1212 | ({{ x }}, {{ y }}) |
| 1213 | {% endwith %} |
1208 | 1214 | """ |
1209 | 1215 | bits = list(token.split_contents()) |
1210 | | if len(bits) != 4 or bits[2] != "as": |
1211 | | raise TemplateSyntaxError("%r expected format is 'value as name'" % |
1212 | | bits[0]) |
1213 | | var = parser.compile_filter(bits[1]) |
1214 | | name = bits[3] |
| 1216 | try: |
| 1217 | if len(bits) % 4: |
| 1218 | raise TemplateSyntaxError() |
| 1219 | for b in bits[2::4]: |
| 1220 | if b != 'as': |
| 1221 | raise TemplateSyntaxError() |
| 1222 | for b in bits[4::4]: |
| 1223 | if b != 'and': |
| 1224 | raise TemplateSyntaxError() |
| 1225 | except TemplateSyntaxError: |
| 1226 | raise TemplateSyntaxError("'%s' statements should use the format " |
| 1227 | "'with value as name [and value as name]...'" |
| 1228 | ": %s" % (bits[0], token.contents)) |
| 1229 | varlist = [parser.compile_filter(b) for b in bits[1::4]] |
| 1230 | namelist = bits[3::4] |
1215 | 1231 | nodelist = parser.parse(('endwith',)) |
1216 | 1232 | parser.delete_first_token() |
1217 | | return WithNode(var, name, nodelist) |
| 1233 | return WithNode(namelist, varlist, nodelist) |
1218 | 1234 | do_with = register.tag('with', do_with) |
diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt
index a20ab17..5f64aa0 100644
a
|
b
|
For example::
|
1040 | 1040 | The populated variable (in the example above, ``total``) is only available |
1041 | 1041 | between the ``{% with %}`` and ``{% endwith %}`` tags. |
1042 | 1042 | |
| 1043 | .. versionadded:: 1.3 |
| 1044 | |
| 1045 | Multiple variables can be cached by using the word ``"and"`` as a delimiter:: |
| 1046 | |
| 1047 | {% with items.0 as first and items|slice:"1:" as rest %} |
| 1048 | {{ first }} comes first and {{ rest|join:", " }} follow. |
| 1049 | {% endwith %} |
| 1050 | |
1043 | 1051 | .. _ref-templates-builtins-filters: |
1044 | 1052 | |
1045 | 1053 | Built-in filter reference |
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
index 9e2d175..06e25ce 100644
a
|
b
|
class Templates(unittest.TestCase):
|
1212 | 1212 | ### WITH TAG ######################################################## |
1213 | 1213 | 'with01': ('{% with dict.key as key %}{{ key }}{% endwith %}', {'dict': {'key':50}}, '50'), |
1214 | 1214 | 'with02': ('{{ key }}{% with dict.key as key %}{{ key }}-{{ dict.key }}-{{ key }}{% endwith %}{{ key }}', {'dict': {'key':50}}, ('50-50-50', 'INVALID50-50-50INVALID')), |
| 1215 | 'with03': ('{% with dict.k1 as k1 and dict.k2 as k2 %}{{ k1 }}+{{ k2 }}{% endwith %}', {'dict': {'k1':3, 'k2':4}}, '3+4'), |
| 1216 | 'with04': ('{% with 42 as z and x|add:5 as y and y as x %}({{ x }},{{ y }},{{ z }}){% endwith %}', {'x': 13, 'y': -5}, '(-5,18,42)'), |
1215 | 1217 | |
1216 | 1218 | 'with-error01': ('{% with dict.key xx key %}{{ key }}{% endwith %}', {'dict': {'key':50}}, template.TemplateSyntaxError), |
1217 | 1219 | 'with-error02': ('{% with dict.key as %}{{ key }}{% endwith %}', {'dict': {'key':50}}, template.TemplateSyntaxError), |
| 1220 | 'with-error03': ('{% with dict.k1 as k1 and dict.k2 %}{{ key }}{% endwith %}', {'dict': {'k1':3, 'k2':4}}, template.TemplateSyntaxError), |
| 1221 | 'with-error04': ('{% with dict.k1 equals k1 %}{{ key }}{% endwith %}', {'dict': {'k1':3, 'k2':4}}, template.TemplateSyntaxError), |
| 1222 | 'with-error05': ('{% with dict.k1 as k1, dict.k2 as k2 %}{{ key }}{% endwith %}', {'dict': {'k1':3, 'k2':4}}, template.TemplateSyntaxError), |
1218 | 1223 | |
1219 | 1224 | ### NOW TAG ######################################################## |
1220 | 1225 | # Simple case |