Simplified caching of template context processors.

This commit is contained in:
Aymeric Augustin 2014-11-18 21:52:09 +01:00
parent a97e72aaab
commit f88ad710fa
4 changed files with 14 additions and 23 deletions

View File

@ -1,8 +1,9 @@
from copy import copy from copy import copy
from django.conf import settings
from django.utils import lru_cache
from django.utils.module_loading import import_string from django.utils.module_loading import import_string
# Cache of actual callables.
_standard_context_processors = None
# Hard-coded processor for easier use of CSRF protection. # Hard-coded processor for easier use of CSRF protection.
_builtin_context_processors = ('django.core.context_processors.csrf',) _builtin_context_processors = ('django.core.context_processors.csrf',)
@ -170,21 +171,11 @@ class RenderContext(BaseContext):
return self.dicts[-1][key] return self.dicts[-1][key]
# This is a function rather than module-level procedural code because we only @lru_cache.lru_cache()
# want it to execute if somebody uses RequestContext.
def get_standard_processors(): def get_standard_processors():
from django.conf import settings context_processors = _builtin_context_processors
global _standard_context_processors context_processors += tuple(settings.TEMPLATE_CONTEXT_PROCESSORS)
if _standard_context_processors is None: return tuple(import_string(path) for path in context_processors)
processors = []
collect = []
collect.extend(_builtin_context_processors)
collect.extend(settings.TEMPLATE_CONTEXT_PROCESSORS)
for path in collect:
func = import_string(path)
processors.append(func)
_standard_context_processors = tuple(processors)
return _standard_context_processors
class RequestContext(Context): class RequestContext(Context):

View File

@ -80,8 +80,8 @@ def update_connections_time_zone(**kwargs):
@receiver(setting_changed) @receiver(setting_changed)
def clear_context_processors_cache(**kwargs): def clear_context_processors_cache(**kwargs):
if kwargs['setting'] == 'TEMPLATE_CONTEXT_PROCESSORS': if kwargs['setting'] == 'TEMPLATE_CONTEXT_PROCESSORS':
from django.template import context from django.template.context import get_standard_processors
context._standard_context_processors = None get_standard_processors.cache_clear()
@receiver(setting_changed) @receiver(setting_changed)

View File

@ -0,0 +1,2 @@
def special(request):
return {'path': request.special_path}

View File

@ -9,7 +9,6 @@ import itertools
from django.core.urlresolvers import reverse, NoReverseMatch from django.core.urlresolvers import reverse, NoReverseMatch
from django.template import TemplateSyntaxError, Context, Template from django.template import TemplateSyntaxError, Context, Template
import django.template.context
from django.test import Client, TestCase, override_settings from django.test import Client, TestCase, override_settings
from django.test.client import encode_file, RequestFactory from django.test.client import encode_file, RequestFactory
from django.test.utils import ContextList, str_prefix from django.test.utils import ContextList, str_prefix
@ -994,12 +993,11 @@ class ContextTests(TestCase):
# Need to insert a context processor that assumes certain things about # Need to insert a context processor that assumes certain things about
# the request instance. This triggers a bug caused by some ways of # the request instance. This triggers a bug caused by some ways of
# copying RequestContext. # copying RequestContext.
try: with self.settings(TEMPLATE_CONTEXT_PROCESSORS=(
django.template.context._standard_context_processors = (lambda request: {'path': request.special_path},) 'test_client_regress.context_processors.special',
)):
response = self.client.get("/request_context_view/") response = self.client.get("/request_context_view/")
self.assertContains(response, 'Path: /request_context_view/') self.assertContains(response, 'Path: /request_context_view/')
finally:
django.template.context._standard_context_processors = None
def test_nested_requests(self): def test_nested_requests(self):
""" """