diff --git a/django/template/context.py b/django/template/context.py index de7c39f17b..cf0c929065 100644 --- a/django/template/context.py +++ b/django/template/context.py @@ -1,5 +1,7 @@ +from copy import copy from django.core.exceptions import ImproperlyConfigured from django.utils.importlib import import_module +from django.http import HttpRequest # Cache of actual callables. _standard_context_processors = None @@ -17,6 +19,11 @@ class BaseContext(object): dict_ = dict_ or {} self.dicts = [dict_] + def __copy__(self): + duplicate = self._new() + duplicate.dicts = [dict_ for dict_ in self.dicts] + return duplicate + def __repr__(self): return repr(self.dicts) @@ -24,6 +31,9 @@ class BaseContext(object): for d in reversed(self.dicts): yield d + def _new(self): + return self.__class__() + def push(self): d = {} self.dicts.append(d) @@ -73,6 +83,16 @@ class Context(BaseContext): self.render_context = RenderContext() super(Context, self).__init__(dict_) + def __copy__(self): + duplicate = super(Context, self).__copy__() + duplicate.render_context = copy(self.render_context) + return duplicate + + def _new(self): + return self.__class__(autoescape=self.autoescape, + current_app=self.current_app, + use_l10n=self.use_l10n) + def update(self, other_dict): "Pushes other_dict to the stack of dictionaries in the Context" if not hasattr(other_dict, '__getitem__'): @@ -148,3 +168,8 @@ class RequestContext(Context): processors = tuple(processors) for processor in get_standard_processors() + processors: self.update(processor(request)) + + def _new(self): + return self.__class__(request=HttpRequest(), + current_app=self.current_app, + use_l10n=self.use_l10n) diff --git a/django/test/client.py b/django/test/client.py index 24fe62764a..dd0d811b02 100644 --- a/django/test/client.py +++ b/django/test/client.py @@ -5,6 +5,7 @@ import os import re import mimetypes import warnings +from copy import copy try: from cStringIO import StringIO except ImportError: @@ -91,9 +92,12 @@ class ClientHandler(BaseHandler): def store_rendered_templates(store, signal, sender, template, context, **kwargs): """ Stores templates and contexts that are rendered. + + The context is copied so that it is an accurate representation at the time + of rendering. """ store.setdefault('templates', []).append(template) - store.setdefault('context', ContextList()).append(context) + store.setdefault('context', ContextList()).append(copy(context)) def encode_multipart(boundary, data): """