diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py
index 1b07413..9be64f0 100644
--- a/django/template/defaulttags.py
+++ b/django/template/defaulttags.py
@@ -417,18 +417,19 @@ class WidthRatioNode(Node):
         return str(int(round(ratio)))
 
 class WithNode(Node):
-    def __init__(self, var, name, nodelist):
-        self.var = var
-        self.name = name
+    def __init__(self, names, vars, nodelist):
+        self.names = names
+        self.vars = vars
         self.nodelist = nodelist
 
     def __repr__(self):
         return "<WithNode>"
 
     def render(self, context):
-        val = self.var.resolve(context)
+        values = [var.resolve(context) for var in self.vars]
         context.push()
-        context[self.name] = val
+        for name, value in zip(self.names, values):
+            context[name] = value
         output = self.nodelist.render(context)
         context.pop()
         return output
@@ -1198,21 +1199,36 @@ widthratio = register.tag(widthratio)
 def do_with(parser, token):
     """
     Adds a value to the context (inside of this block) for caching and easy
-    access.
+    access. You can bind a value to a new name using ``as``. You can chain
+    multiple bindings with ``and``. You can also safely swap variables.
 
     For example::
 
         {% with person.some_sql_method as total %}
             {{ total }} object{{ total|pluralize }}
         {% endwith %}
+
+        {% with x|add:5 as y and y as x %}
+            ({{ x }}, {{ y }})
+        {% endwith %}
     """
     bits = list(token.split_contents())
-    if len(bits) != 4 or bits[2] != "as":
-        raise TemplateSyntaxError("%r expected format is 'value as name'" %
-                                  bits[0])
-    var = parser.compile_filter(bits[1])
-    name = bits[3]
+    try:
+        if len(bits) % 4:
+            raise TemplateSyntaxError()
+        for b in bits[2::4]:
+            if b != 'as':
+                raise TemplateSyntaxError()
+        for b in bits[4::4]:
+            if b != 'and':
+                raise TemplateSyntaxError()
+    except TemplateSyntaxError:
+        raise TemplateSyntaxError("'%s' statements should use the format "
+                                  "'with value as name [and value as name]...'"
+                                  ": %s" % (bits[0], token.contents))
+    varlist = [parser.compile_filter(b) for b in bits[1::4]]
+    namelist = bits[3::4]
     nodelist = parser.parse(('endwith',))
     parser.delete_first_token()
-    return WithNode(var, name, nodelist)
+    return WithNode(namelist, varlist, nodelist)
 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/docs/ref/templates/builtins.txt
+++ b/docs/ref/templates/builtins.txt
@@ -1040,6 +1040,14 @@ For example::
 The populated variable (in the example above, ``total``) is only available
 between the ``{% with %}`` and ``{% endwith %}`` tags.
 
+.. versionadded:: 1.3
+
+Multiple variables can be cached by using the word ``"and"`` as a delimiter::
+
+    {% with items.0 as first and items|slice:"1:" as rest %}
+        {{ first }} comes first and {{ rest|join:", " }} follow.
+    {% endwith %}
+
 .. _ref-templates-builtins-filters:
 
 Built-in filter reference
diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py
index 9e2d175..06e25ce 100644
--- a/tests/regressiontests/templates/tests.py
+++ b/tests/regressiontests/templates/tests.py
@@ -1212,9 +1212,14 @@ class Templates(unittest.TestCase):
             ### WITH TAG ########################################################
             'with01': ('{% with dict.key as key %}{{ key }}{% endwith %}', {'dict': {'key':50}}, '50'),
             'with02': ('{{ key }}{% with dict.key as key %}{{ key }}-{{ dict.key }}-{{ key }}{% endwith %}{{ key }}', {'dict': {'key':50}}, ('50-50-50', 'INVALID50-50-50INVALID')),
+            'with03': ('{% with dict.k1 as k1 and dict.k2 as k2 %}{{ k1 }}+{{ k2 }}{% endwith %}', {'dict': {'k1':3, 'k2':4}}, '3+4'),
+            '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)'),
 
             'with-error01': ('{% with dict.key xx key %}{{ key }}{% endwith %}', {'dict': {'key':50}}, template.TemplateSyntaxError),
             'with-error02': ('{% with dict.key as %}{{ key }}{% endwith %}', {'dict': {'key':50}}, template.TemplateSyntaxError),
+            'with-error03': ('{% with dict.k1 as k1 and dict.k2 %}{{ key }}{% endwith %}', {'dict': {'k1':3, 'k2':4}}, template.TemplateSyntaxError),
+            'with-error04': ('{% with dict.k1 equals k1 %}{{ key }}{% endwith %}', {'dict': {'k1':3, 'k2':4}}, template.TemplateSyntaxError),
+            'with-error05': ('{% with dict.k1 as k1, dict.k2 as k2 %}{{ key }}{% endwith %}', {'dict': {'k1':3, 'k2':4}}, template.TemplateSyntaxError),
 
             ### NOW TAG ########################################################
             # Simple case
