Ticket #1065: fragment_caching.diff

File fragment_caching.diff, 5.7 KB (added by nick.lane.au@…, 17 years ago)

Combined patches and added some tests.

  • django/templatetags/fragment_caching.py

    === added file 'django/templatetags/fragment_caching.py'
     
     1from django.template import Library, Node, TemplateSyntaxError
     2from django.template import resolve_variable
     3from django.core.cache import cache
     4from django.utils.encoding import force_unicode
     5
     6register = Library()
     7
     8class CacheNode(Node):
     9    def __init__(self, nodelist, expire_time, fragment_name, vary_on):
     10        self.nodelist = nodelist
     11        self.expire_time = expire_time
     12        self.fragment_name = fragment_name
     13        self.vary_on = vary_on
     14
     15    def render(self, context):
     16        # Build a unicode key for this fragment and all vary-on's.
     17        cache_key = u':'.join([self.fragment_name] + \
     18            [force_unicode(resolve_variable(var, context)) for var in self.vary_on])
     19        value = cache.get(cache_key)
     20        if value is None:
     21            value = self.nodelist.render(context)
     22            cache.set(cache_key, value, self.expire_time)
     23        return value
     24
     25def do_cache(parser, token):
     26    """
     27    This will cache the contents of a template fragment for a given amount
     28    of time.
     29
     30    Usage::
     31
     32        {% load fragment_caching %}
     33        {% cache [expire_time] [fragment_name] %}
     34            .. some expensive processing ..
     35        {% endcache %}
     36
     37    This tag also supports varying by a list of arguments::
     38
     39        {% load fragment_caching %}
     40        {% cache [expire_time] [fragment_name] [var1] [var2] .. %}
     41            .. some expensive processing ..
     42        {% endcache %}
     43
     44    Each unique set of arguments will result in a unique cache entry.
     45    """
     46    nodelist = parser.parse(('endcache',))
     47    parser.delete_first_token()
     48    tokens = token.contents.split()
     49    if len(tokens) < 3:
     50        raise TemplateSyntaxError(u"'%r' tag requires at least 2 arguments." % tokens[0])
     51    try:
     52        expire_time = int(tokens[1])
     53    except ValueError:
     54        raise TemplateSyntaxError(u"First argument to '%r' must be an integer (got '%s')." % (tokens[0], tokens[1]))
     55    return CacheNode(nodelist, expire_time, tokens[2], tokens[3:])
     56
     57register.tag('cache', do_cache)
  • docs/cache.txt

    === modified file 'docs/cache.txt'
     
    286286above example, the result of the ``slashdot_this()`` view will be cached for 15
    287287minutes.
    288288
     289Fragment caching
     290================
     291
     292If you're after even more control, you can also easily cache template fragments
     293using the ``cache`` template tag. To give your template access to this tag, put
     294``{% load fragment_caching %}`` near the top of your template.
     295
     296The ``{% cache %}`` template tag caches the contents of the block for a given
     297amount of time and takes at least two arguments. The first argument is the
     298cache timeout, in seconds. The second argument is the name to give the cache
     299fragment. For example::
     300
     301    {% load fragment_caching %}
     302    {% cache 500 sidebar %}
     303        .. sidebar ..
     304    {% endcache %}
     305
     306Sometimes you might want to cache multiple copies of a fragment depending on
     307some dynamic data that appears inside the fragment. For example you may want a
     308separate cached copy of the sidebar used in the previous example for every user
     309of your site. This can be easily achieved by passing additional arguments to
     310the ``{% cache %}`` template tag to uniquely identify the cache fragment::
     311
     312    {% load fragment_caching %}
     313    {% cache 500 sidebar request.user.username %}
     314        .. sidebar for logged in user ..
     315    {% endcache %}
     316
     317If you need more than one argument to identify the fragment that's fine, simply
     318pass as many arguments to ``{% cache %}`` as you need!
     319
    289320The low-level cache API
    290321=======================
    291322
  • tests/regressiontests/templates/tests.py

    === modified file 'tests/regressiontests/templates/tests.py'
     
    741741            'url-fail01' : ('{% url %}', {}, template.TemplateSyntaxError),
    742742            'url-fail02' : ('{% url no_such_view %}', {}, ''),
    743743            'url-fail03' : ('{% url regressiontests.templates.views.client no_such_param="value" %}', {}, ''),
     744
     745            ### FRAGMENT CACHING ###############################################
     746            'cache01' : ('{% load fragment_caching %}{% cache -1 test %}cache01{% endcache %}', {}, 'cache01'),
     747            'cache02' : ('{% load fragment_caching %}{% cache -1 test %}cache02{% endcache %}', {}, 'cache02'),
     748            'cache03' : ('{% load fragment_caching %}{% cache 100 test %}cache03{% endcache %}', {}, 'cache03'),
     749            'cache04' : ('{% load fragment_caching %}{% cache 100 test %}cache04{% endcache %}', {}, 'cache03'),
     750            'cache05' : ('{% load fragment_caching %}{% cache 100 test foo %}cache05{% endcache %}', {'foo': 1}, 'cache05'),
     751            'cache06' : ('{% load fragment_caching %}{% cache 100 test foo %}cache06{% endcache %}', {'foo': 2}, 'cache06'),
     752            'cache07' : ('{% load fragment_caching %}{% cache 100 test foo %}cache06{% endcache %}', {'foo': 1}, 'cache05'),
     753
     754            # Raise exception if we dont have at least 2 args, first one integer.
     755            'cache08' : ('{% load fragment_caching %}{% cache %}{% endcache %}', {}, template.TemplateSyntaxError),
     756            'cache09' : ('{% load fragment_caching %}{% cache 1 %}{% endcache %}', {}, template.TemplateSyntaxError),
     757            'cache10' : ('{% load fragment_caching %}{% cache foo bar %}{% endcache %}', {}, template.TemplateSyntaxError),
    744758        }
    745759
    746760        # Register our custom template loader.
Back to Top