Ticket #9874: template-cache.diff

File template-cache.diff, 6.9 KB (added by groks, 6 years ago)

Fixes for cache key name, thread safety. Adds config, tests.

  • django/conf/global_settings.py

    diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
    a b TEMPLATE_CONTEXT_PROCESSORS = ( 
    171171# Output to use in template system for invalid (e.g. misspelled) variables.
    172172TEMPLATE_STRING_IF_INVALID = ''
    173173
     174# Whether to cache compiled templates in global memory. This setting has no
     175# effect when TEMPLATE_DEBUG is enabled.
     176TEMPLATE_CACHE = False
     177
    174178# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
    175179# trailing slash.
    176180# Examples: "http://foo.com/media/", "/media/".
  • django/template/loader.py

    diff --git a/django/template/loader.py b/django/template/loader.py
    a b from django.core.exceptions import Impro 
    2424from django.template import Origin, Template, Context, TemplateDoesNotExist, add_to_builtins
    2525from django.utils.importlib import import_module
    2626from django.conf import settings
     27from threading import Lock
    2728
    2829template_source_loaders = None
    2930
     31cache_lock = Lock()
     32template_cache = {}
     33
    3034class LoaderOrigin(Origin):
    3135    def __init__(self, display_name, loader, name, dirs):
    3236        super(LoaderOrigin, self).__init__(display_name)
    def find_template_source(name, dirs=None 
    7377            pass
    7478    raise TemplateDoesNotExist, name
    7579
    76 def get_template(template_name):
     80def get_template(template_name, dirs=None):
    7781    """
    7882    Returns a compiled Template object for the given template name,
    7983    handling template inheritance recursively.
     84
     85    The compiled template may be cached for future speedy lookup.
    8086    """
    81     source, origin = find_template_source(template_name)
    82     template = get_template_from_string(source, origin, template_name)
     87    global cache_lock, template_cache
     88
     89    def get_new_template(template_name, dirs):
     90        source, origin = find_template_source(template_name, dirs)
     91        return get_template_from_string(source, origin, template_name)
     92
     93    if isinstance(dirs, list):
     94        dirs = tuple(dirs)
     95
     96    if settings.TEMPLATE_DEBUG or (not settings.TEMPLATE_CACHE):
     97        template = get_new_template(template_name, dirs)
     98    else:
     99        cache_lock.acquire()
     100        try:
     101            try:
     102                template = template_cache[(template_name, dirs)]
     103            except KeyError:
     104                template = get_new_template(template_name, dirs)
     105                template_cache[(template_name, dirs)] = template
     106        finally:
     107            cache_lock.release()
     108
    83109    return template
    84110
    85111def get_template_from_string(source, origin=None, name=None):
  • django/template/loader_tags.py

    diff --git a/django/template/loader_tags.py b/django/template/loader_tags.py
    a b  
    11from django.template import TemplateSyntaxError, TemplateDoesNotExist, Variable
    22from django.template import Library, Node, TextNode
    3 from django.template.loader import get_template, get_template_from_string, find_template_source
     3from django.template.loader import get_template
    44from django.conf import settings
    55from django.utils.safestring import mark_safe
    66
    class ExtendsNode(Node): 
    6161        if hasattr(parent, 'render'):
    6262            return parent # parent is a Template object
    6363        try:
    64             source, origin = find_template_source(parent, self.template_dirs)
     64            parent_template = get_template(parent, self.template_dirs)
    6565        except TemplateDoesNotExist:
    66             raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent
    67         else:
    68             return get_template_from_string(source, origin, parent)
     66            raise TemplateSyntaxError, "Template '%r' cannot be extended, because it doesn't exist" % parent
     67        return parent_template
    6968
    7069    def render(self, context):
    7170        compiled_parent = self.get_parent(context)
  • docs/ref/settings.txt

    diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
    a b Default:: 
    10511051A tuple of callables (as strings) that know how to import templates from
    10521052various sources. See :ref:`ref-templates-api`.
    10531053
     1054.. setting:: TEMPLATE_GLOBAL_CACHE
     1055
     1056TEMPLATE_CACHE
     1057---------------------
     1058
     1059Default: ``False``
     1060
     1061A boolean that turns on/off the template cache. If this is ``True`` and
     1062``TEMPLATE_DEBUG`` is not enabled, templates will be loaded, compiled, and
     1063the compiled form cached for future requests. This is a speed optimization.
     1064
     1065You will need to restart your server if you change a template with this
     1066setting enabled and ``TEMPLATE_DEBUG`` dissabled.
     1067
     1068Templates are cached in memory. Do not enable this if you have a template
     1069loader which could load a potentially unbounded number of templates, say
     1070from a database.
     1071
     1072See also ``TEMPLATE_DEBUG``.
     1073
    10541074.. setting:: TEMPLATE_STRING_IF_INVALID
    10551075
    10561076TEMPLATE_STRING_IF_INVALID
  • tests/regressiontests/templates/loaders.py

    diff --git a/tests/regressiontests/templates/loaders.py b/tests/regressiontests/templates/loaders.py
    a b class EggLoader(unittest.TestCase): 
    8989        settings.INSTALLED_APPS = []
    9090        self.assertRaises(TemplateDoesNotExist, lts_egg, "y.html")
    9191
     92
     93from django.template.loader import template_cache, get_template
     94
     95class CachedLoaders(unittest.TestCase):
     96    def setUp(self):
     97        global template_cache
     98        template_cache.clear()
     99        self._template_cache = settings.TEMPLATE_CACHE
     100        self._template_debug = settings.TEMPLATE_DEBUG
     101
     102    def tearDown(self):
     103        settings.TEMPLATE_CACHE = self._template_cache
     104        settings.TEMPLATE_DEBUG = self._template_debug
     105
     106    def test_enabled(self):
     107        "Load a template with caching enabled and debug dissabled"
     108        settings.TEMPLATE_DEBUG = False
     109        settings.TEMPLATE_CACHE = True
     110        global template_cache
     111        self.assertEqual(len(template_cache), 0)
     112        t = get_template("base.html")
     113        t = get_template("base.html")
     114        self.assertEqual(len(template_cache), 1)
     115        template_name, dirs = template_cache.keys()[0]
     116        self.assertEqual(template_name, "base.html")
     117        self.assertEqual(dirs, None)
     118
     119    def test_disabled(self):
     120        "Load a template with caching dissabled"
     121        settings.TEMPLATE_CACHE = False
     122        settings.TEMPLATE_DEBUG = False
     123        global template_cache
     124        self.assertEqual(len(template_cache), 0)
     125        t = get_template("base.html")
     126        t = get_template("base.html")
     127        self.assertEqual(len(template_cache), 0)
     128
     129    def test_debug(self):
     130        "Load a template with caching dissabled by debugging"
     131        settings.TEMPLATE_CACHE = True
     132        settings.TEMPLATE_DEBUG = True
     133        global template_cache
     134        self.assertEqual(len(template_cache), 0)
     135        t = get_template("base.html")
     136        t = get_template("base.html")
     137        self.assertEqual(len(template_cache), 0)
     138
     139
    92140if __name__ == "__main__":
    93141    unittest.main()
Back to Top