You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cache.py 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. from django.core.cache import InvalidCacheBackendError, caches
  2. from django.core.cache.utils import make_template_fragment_key
  3. from django.template import (
  4. Library, Node, TemplateSyntaxError, VariableDoesNotExist,
  5. )
  6. register = Library()
  7. class CacheNode(Node):
  8. def __init__(self, nodelist, expire_time_var, fragment_name, vary_on, cache_name):
  9. self.nodelist = nodelist
  10. self.expire_time_var = expire_time_var
  11. self.fragment_name = fragment_name
  12. self.vary_on = vary_on
  13. self.cache_name = cache_name
  14. def render(self, context):
  15. try:
  16. expire_time = self.expire_time_var.resolve(context)
  17. except VariableDoesNotExist:
  18. raise TemplateSyntaxError('"cache" tag got an unknown variable: %r' % self.expire_time_var.var)
  19. if expire_time is not None:
  20. try:
  21. expire_time = int(expire_time)
  22. except (ValueError, TypeError):
  23. raise TemplateSyntaxError('"cache" tag got a non-integer timeout value: %r' % expire_time)
  24. if self.cache_name:
  25. try:
  26. cache_name = self.cache_name.resolve(context)
  27. except VariableDoesNotExist:
  28. raise TemplateSyntaxError('"cache" tag got an unknown variable: %r' % self.cache_name.var)
  29. try:
  30. fragment_cache = caches[cache_name]
  31. except InvalidCacheBackendError:
  32. raise TemplateSyntaxError('Invalid cache name specified for cache tag: %r' % cache_name)
  33. else:
  34. try:
  35. fragment_cache = caches['template_fragments']
  36. except InvalidCacheBackendError:
  37. fragment_cache = caches['default']
  38. vary_on = [var.resolve(context) for var in self.vary_on]
  39. cache_key = make_template_fragment_key(self.fragment_name, vary_on)
  40. value = fragment_cache.get(cache_key)
  41. if value is None:
  42. value = self.nodelist.render(context)
  43. fragment_cache.set(cache_key, value, expire_time)
  44. return value
  45. @register.tag('cache')
  46. def do_cache(parser, token):
  47. """
  48. This will cache the contents of a template fragment for a given amount
  49. of time.
  50. Usage::
  51. {% load cache %}
  52. {% cache [expire_time] [fragment_name] %}
  53. .. some expensive processing ..
  54. {% endcache %}
  55. This tag also supports varying by a list of arguments::
  56. {% load cache %}
  57. {% cache [expire_time] [fragment_name] [var1] [var2] .. %}
  58. .. some expensive processing ..
  59. {% endcache %}
  60. Optionally the cache to use may be specified thus::
  61. {% cache .... using="cachename" %}
  62. Each unique set of arguments will result in a unique cache entry.
  63. """
  64. nodelist = parser.parse(('endcache',))
  65. parser.delete_first_token()
  66. tokens = token.split_contents()
  67. if len(tokens) < 3:
  68. raise TemplateSyntaxError("'%r' tag requires at least 2 arguments." % tokens[0])
  69. if len(tokens) > 3 and tokens[-1].startswith('using='):
  70. cache_name = parser.compile_filter(tokens[-1][len('using='):])
  71. tokens = tokens[:-1]
  72. else:
  73. cache_name = None
  74. return CacheNode(
  75. nodelist, parser.compile_filter(tokens[1]),
  76. tokens[2], # fragment_name can't be a variable.
  77. [parser.compile_filter(t) for t in tokens[3:]],
  78. cache_name,
  79. )