Index: django/template/__init__.py
===================================================================
--- django/template/__init__.py	(revision 7684)
+++ django/template/__init__.py	(working copy)
@@ -196,8 +196,8 @@
             ({TOKEN_TEXT: 'Text', TOKEN_VAR: 'Var', TOKEN_BLOCK: 'Block', TOKEN_COMMENT: 'Comment'}[self.token_type],
             self.contents[:20].replace('\n', ''))
 
-    def split_contents(self):
-        return list(smart_split(self.contents))
+    def split_contents(self, yield_comma=False):
+        return list(smart_split(self.contents, yield_comma=yield_comma))
 
 class Lexer(object):
     def __init__(self, template_string, origin):
@@ -898,11 +898,10 @@
                     dict = func(*args)
 
                     if not getattr(self, 'nodelist', False):
-                        from django.template.loader import get_template, select_template
                         if not isinstance(file_name, basestring) and is_iterable(file_name):
-                            t = select_template(file_name)
+                            t = context.select_template(file_name)
                         else:
-                            t = get_template(file_name)
+                            t = context.get_template(file_name)
                         self.nodelist = t.nodelist
                     return self.nodelist.render(context_class(dict,
                             autoescape=context.autoescape))
@@ -927,6 +926,16 @@
             raise InvalidTemplateLibrary("Template library %s does not have a variable named 'register'" % module_name)
     return lib
 
+def render_with_context_map(renderable, context_map, context):
+    dict = {}
+    for name in context_map:
+        dict[name] = context_map[name].resolve(context)
+    context.update(dict)
+    output = renderable.render(context)
+    context.pop()
+    return output
+
+
 def add_to_builtins(module_name):
     builtins.append(get_library(module_name))
 
Index: django/template/defaulttags.py
===================================================================
--- django/template/defaulttags.py	(revision 7684)
+++ django/template/defaulttags.py	(working copy)
@@ -11,6 +11,7 @@
 from django.template import Node, NodeList, Template, Context, Variable
 from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
 from django.template import get_library, Library, InvalidTemplateLibrary
+from django.template import render_with_context_map
 from django.conf import settings
 from django.utils.encoding import smart_str, smart_unicode
 from django.utils.itercompat import groupby
@@ -390,21 +391,15 @@
         return str(int(round(ratio)))
 
 class WithNode(Node):
-    def __init__(self, var, name, nodelist):
-        self.var = var
-        self.name = name
+    def __init__(self, context_map, nodelist):
+        self.context_map = context_map
         self.nodelist = nodelist
 
     def __repr__(self):
         return "<WithNode>"
 
     def render(self, context):
-        val = self.var.resolve(context)
-        context.push()
-        context[self.name] = val
-        output = self.nodelist.render(context)
-        context.pop()
-        return output
+        return render_with_context_map(self.nodelist, self.context_map, context)
 
 #@register.tag
 def autoescape(parser, token):
@@ -1091,13 +1086,23 @@
             {{ total }} object{{ total|pluralize }}
         {% endwith %}
     """
-    bits = list(token.split_contents())
-    if len(bits) != 4 or bits[2] != "as":
-        raise TemplateSyntaxError("%r expected format is 'value as name'" %
+    bits = list(token.split_contents(yield_comma=True))
+
+    context_map = {}
+    syntax_error = False
+    if len(bits) % 4 == 0:
+    	for i in range(len(bits)/4):
+    		and_, value, as_, name = bits[4*i:4*(i+1)]
+    		if i != 0 and and_ not in ('and', ',') or as_ != 'as':
+    			syntax_error = True
+    		context_map[name] = parser.compile_filter(value)
+    else:
+    	syntax_error = True
+
+    if syntax_error:
+        raise TemplateSyntaxError("%r expected format is 'value as name (and value as name)*'" %
                                   bits[0])
-    var = parser.compile_filter(bits[1])
-    name = bits[3]
     nodelist = parser.parse(('endwith',))
     parser.delete_first_token()
-    return WithNode(var, name, nodelist)
+    return WithNode(context_map, nodelist)
 do_with = register.tag('with', do_with)
Index: django/template/context.py
===================================================================
--- django/template/context.py	(revision 7684)
+++ django/template/context.py	(working copy)
@@ -9,10 +9,12 @@
 
 class Context(object):
     "A stack container for variable context"
-    def __init__(self, dict_=None, autoescape=True):
+    def __init__(self, dict_=None, autoescape=True, loader=None):
         dict_ = dict_ or {}
         self.dicts = [dict_]
         self.autoescape = autoescape
+        self.template_cache = {}
+        self.loader = loader
 
     def __repr__(self):
         return repr(self.dicts)
@@ -65,6 +67,25 @@
         self.dicts = [other_dict] + self.dicts
         return other_dict
 
+    def get_template(self, template_name):
+        if not template_name in self.template_cache:
+            if self.loader is None:
+                from django.template import loader
+                tpl = loader.get_template(template_name)
+            else:
+                tpl = self.loader.get_template(template_name)
+            self.template_cache[template_name] = tpl
+        return self.template_cache[template_name]
+
+    def select_template(self, template_name_list):
+        from django.template import TemplateDoesNotExist
+        for template_name in template_name_list:
+            try:
+                return self.get_template(template_name)
+            except TemplateDoesNotExist:
+                continue
+        raise TemplateDoesNotExist, ', '.join(template_name_list)
+
 # This is a function rather than module-level procedural code because we only
 # want it to execute if somebody uses RequestContext.
 def get_standard_processors():
@@ -93,8 +114,8 @@
     Additional processors can be specified as a list of callables
     using the "processors" keyword argument.
     """
-    def __init__(self, request, dict=None, processors=None):
-        Context.__init__(self, dict)
+    def __init__(self, request, dict=None, processors=None, loader=None):
+        Context.__init__(self, dict, loader=loader)
         if processors is None:
             processors = ()
         else:
Index: django/template/loader_tags.py
===================================================================
--- django/template/loader_tags.py	(revision 7684)
+++ django/template/loader_tags.py	(working copy)
@@ -39,10 +39,9 @@
 class ExtendsNode(Node):
     must_be_first = True
 
-    def __init__(self, nodelist, parent_name, parent_name_expr, template_dirs=None):
+    def __init__(self, nodelist, parent_name, parent_name_expr):
         self.nodelist = nodelist
         self.parent_name, self.parent_name_expr = parent_name, parent_name_expr
-        self.template_dirs = template_dirs
 
     def __repr__(self):
         if self.parent_name_expr:
@@ -61,11 +60,9 @@
         if hasattr(parent, 'render'):
             return parent # parent is a Template object
         try:
-            source, origin = find_template_source(parent, self.template_dirs)
+            return context.get_template(parent)
         except TemplateDoesNotExist:
             raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent
-        else:
-            return get_template_from_string(source, origin, parent)
 
     def render(self, context):
         compiled_parent = self.get_parent(context)
@@ -92,22 +89,6 @@
                 parent_block.nodelist = block_node.nodelist
         return compiled_parent.render(context)
 
-class ConstantIncludeNode(Node):
-    def __init__(self, template_path):
-        try:
-            t = get_template(template_path)
-            self.template = t
-        except:
-            if settings.TEMPLATE_DEBUG:
-                raise
-            self.template = None
-
-    def render(self, context):
-        if self.template:
-            return self.template.render(context)
-        else:
-            return ''
-
 class IncludeNode(Node):
     def __init__(self, template_name):
         self.template_name = Variable(template_name)
@@ -115,8 +96,8 @@
     def render(self, context):
         try:
             template_name = self.template_name.resolve(context)
-            t = get_template(template_name)
-            return t.render(context)
+            tpl = context.get_template(template_name)
+            return tpl.render(context)
         except TemplateSyntaxError, e:
             if settings.TEMPLATE_DEBUG:
                 raise
@@ -178,9 +159,6 @@
     bits = token.contents.split()
     if len(bits) != 2:
         raise TemplateSyntaxError, "%r tag takes one argument: the name of the template to be included" % bits[0]
-    path = bits[1]
-    if path[0] in ('"', "'") and path[-1] == path[0]:
-        return ConstantIncludeNode(path[1:-1])
     return IncludeNode(bits[1])
 
 register.tag('block', do_block)
Index: django/utils/text.py
===================================================================
--- django/utils/text.py	(revision 7684)
+++ django/utils/text.py	(working copy)
@@ -196,8 +196,10 @@
     return str(ustring_re.sub(fix, s))
 javascript_quote = allow_lazy(javascript_quote, unicode)
 
-smart_split_re = re.compile('("(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'|[^\\s]+)')
-def smart_split(text):
+quoted_string_pattern = '"(?:[^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'(?:[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\''
+smart_split_re = re.compile('(%s|[^\\s]+)' % quoted_string_pattern)
+smart_split_comma_re = re.compile('(%s|[^\\s,]+|,)' % quoted_string_pattern)
+def smart_split(text, yield_comma=False):
     r"""
     Generator that splits a string by spaces, leaving quoted phrases together.
     Supports both single and double quotes, and supports escaping quotes with
@@ -212,7 +214,8 @@
    	[u'A', u'""funky" style"', u'test.']
     """
     text = force_unicode(text)
-    for bit in smart_split_re.finditer(text):
+    regexp = yield_comma and smart_split_comma_re or smart_split_re
+    for bit in regexp.finditer(text):
         bit = bit.group(0)
         if bit[0] == '"' and bit[-1] == '"':
             yield '"' + bit[1:-1].replace('\\"', '"').replace('\\\\', '\\') + '"'
