jinja2ext.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. """
  2. flask_caching.jinja2ext
  3. ~~~~~~~~~~~~~~~~~~~~~~~
  4. Jinja2 extension that adds support for caching template fragments.
  5. Usage::
  6. {% cache timeout key1[, [key2, ...]] %}
  7. ...
  8. {% endcache %}
  9. By default, the value of "path to template file" + "block start line"
  10. is used as the cache key. Also, the key name can be set manually.
  11. Keys are concatenated together into a single string, that can be used
  12. to avoid the same block evaluating in different templates.
  13. Set the timeout to ``None`` for no timeout, but with custom keys::
  14. {% cache None "key" %}
  15. ...
  16. {% endcache %}
  17. Set timeout to ``del`` to delete cached value::
  18. {% cache 'del' key1 %}
  19. ...
  20. {% endcache %}
  21. Considering we have ``render_form_field`` and ``render_submit`` macros::
  22. {% cache 60*5 'myform' %}
  23. <div>
  24. <form>
  25. {% render_form_field(form.username) %}
  26. {% render_submit() %}
  27. </form>
  28. </div>
  29. {% endcache %}
  30. :copyright: (c) 2010 by Thadeus Burgess.
  31. :license: BSD, see LICENSE for more details.
  32. """
  33. from jinja2 import nodes
  34. from jinja2.ext import Extension
  35. from flask_caching import make_template_fragment_key
  36. JINJA_CACHE_ATTR_NAME = "_template_fragment_cache"
  37. class CacheExtension(Extension):
  38. tags = {"cache"}
  39. def parse(self, parser):
  40. lineno = next(parser.stream).lineno
  41. #: Parse timeout
  42. args = [parser.parse_expression()]
  43. #: Parse fragment name
  44. #: Grab the fragment name if it exists
  45. #: otherwise, default to the old method of using the templates
  46. #: lineno to maintain backwards compatibility.
  47. if parser.stream.skip_if("comma"):
  48. args.append(parser.parse_expression())
  49. else:
  50. args.append(nodes.Const(f"{parser.filename}{lineno}"))
  51. #: Parse vary_on parameters
  52. vary_on = []
  53. while parser.stream.skip_if("comma"):
  54. vary_on.append(parser.parse_expression())
  55. if vary_on:
  56. args.append(nodes.List(vary_on))
  57. else:
  58. args.append(nodes.Const([]))
  59. body = parser.parse_statements(["name:endcache"], drop_needle=True)
  60. return nodes.CallBlock(
  61. self.call_method("_cache", args), [], [], body
  62. ).set_lineno(lineno)
  63. def _cache(self, timeout, fragment_name, vary_on, caller):
  64. try:
  65. cache = getattr(self.environment, JINJA_CACHE_ATTR_NAME)
  66. except AttributeError as e:
  67. raise e
  68. key = make_template_fragment_key(fragment_name, vary_on=vary_on)
  69. #: Delete key if timeout is 'del'
  70. if timeout == "del":
  71. cache.delete(key)
  72. return caller()
  73. rv = cache.get(key)
  74. if rv is None:
  75. rv = caller()
  76. cache.set(key, rv, timeout)
  77. return rv