diff --git a/django/template/context.py b/django/template/context.py index bcfaa3bf9e..acc5758f75 100644 --- a/django/template/context.py +++ b/django/template/context.py @@ -14,21 +14,16 @@ class ContextPopException(Exception): "pop() has been called more times than push()" pass -class EmptyClass(object): - # No-op class which takes no args to its __init__ method, to help implement - # __copy__ - pass - class BaseContext(object): def __init__(self, dict_=None): - dict_ = dict_ or {} - self.dicts = [dict_] + self._reset_dicts(dict_) + + def _reset_dicts(self, value=None): + self.dicts = [value or {}] def __copy__(self): - duplicate = EmptyClass() - duplicate.__class__ = self.__class__ - duplicate.__dict__ = self.__dict__.copy() - duplicate.dicts = duplicate.dicts[:] + duplicate = copy(super(BaseContext, self)) + duplicate.dicts = self.dicts[:] return duplicate def __repr__(self): @@ -78,6 +73,15 @@ class BaseContext(object): return d[key] return otherwise + def new(self, values=None): + """ + Returns a new context with the same properties, but with only the + values given in 'values' stored. + """ + new_context = copy(self) + new_context._reset_dicts(values) + return new_context + class Context(BaseContext): "A stack container for variable context" def __init__(self, dict_=None, autoescape=True, current_app=None, use_l10n=None): @@ -88,7 +92,7 @@ class Context(BaseContext): super(Context, self).__init__(dict_) def __copy__(self): - duplicate = super(Context, self).__copy__() + duplicate = copy(super(Context, self)) duplicate.render_context = copy(self.render_context) return duplicate @@ -99,14 +103,6 @@ class Context(BaseContext): self.dicts.append(other_dict) return other_dict - def new(self, values=None): - """ - Returns a new Context with the same 'autoescape' value etc, but with - only the values given in 'values' stored. - """ - return self.__class__(dict_=values, autoescape=self.autoescape, - current_app=self.current_app, use_l10n=self.use_l10n) - class RenderContext(BaseContext): """ A stack container for storing Template state. diff --git a/tests/regressiontests/templates/tests.py b/tests/regressiontests/templates/tests.py index a051d7335e..dedd7d5c92 100644 --- a/tests/regressiontests/templates/tests.py +++ b/tests/regressiontests/templates/tests.py @@ -1639,5 +1639,34 @@ class TemplateTagLoading(unittest.TestCase): settings.INSTALLED_APPS = ('tagsegg',) t = template.Template(ttext) + +class RequestContextTests(BaseTemplateResponseTest): + + def setUp(self): + templates = { + 'child': Template('{{ var|default:"none" }}'), + } + setup_test_template_loader(templates) + self.fake_request = RequestFactory().get('/') + + def tearDown(self): + restore_template_loaders() + + def test_include_only(self): + """ + Regression test for #15721, ``{% include %}`` and ``RequestContext`` + not playing together nicely. + """ + ctx = RequestContext(self.fake_request, {'var': 'parent'}) + self.assertEqual( + template.Template('{% include "child" %}').render(ctx), + 'parent' + ) + self.assertEqual( + template.Template('{% include "child" only %}').render(ctx), + 'none' + ) + + if __name__ == "__main__": unittest.main()