test_extends.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. import os
  2. from django.template import Context, Engine, TemplateDoesNotExist
  3. from django.template.loader_tags import ExtendsError
  4. from django.template.loaders.base import Loader
  5. from django.test import SimpleTestCase, ignore_warnings
  6. from django.utils.deprecation import RemovedInDjango20Warning
  7. from .utils import ROOT
  8. RECURSIVE = os.path.join(ROOT, 'recursive_templates')
  9. class ExtendsBehaviorTests(SimpleTestCase):
  10. def test_normal_extend(self):
  11. engine = Engine(dirs=[os.path.join(RECURSIVE, 'fs')])
  12. template = engine.get_template('one.html')
  13. output = template.render(Context({}))
  14. self.assertEqual(output.strip(), 'three two one')
  15. def test_extend_recursive(self):
  16. engine = Engine(dirs=[
  17. os.path.join(RECURSIVE, 'fs'),
  18. os.path.join(RECURSIVE, 'fs2'),
  19. os.path.join(RECURSIVE, 'fs3'),
  20. ])
  21. template = engine.get_template('recursive.html')
  22. output = template.render(Context({}))
  23. self.assertEqual(output.strip(), 'fs3/recursive fs2/recursive fs/recursive')
  24. def test_extend_missing(self):
  25. engine = Engine(dirs=[os.path.join(RECURSIVE, 'fs')])
  26. template = engine.get_template('extend-missing.html')
  27. with self.assertRaises(TemplateDoesNotExist) as e:
  28. template.render(Context({}))
  29. tried = e.exception.tried
  30. self.assertEqual(len(tried), 1)
  31. self.assertEqual(tried[0][0].template_name, 'missing.html')
  32. def test_recursive_multiple_loaders(self):
  33. engine = Engine(
  34. dirs=[os.path.join(RECURSIVE, 'fs')],
  35. loaders=[(
  36. 'django.template.loaders.locmem.Loader', {
  37. 'one.html': (
  38. '{% extends "one.html" %}{% block content %}{{ block.super }} locmem-one{% endblock %}'
  39. ),
  40. 'two.html': (
  41. '{% extends "two.html" %}{% block content %}{{ block.super }} locmem-two{% endblock %}'
  42. ),
  43. 'three.html': (
  44. '{% extends "three.html" %}{% block content %}{{ block.super }} locmem-three{% endblock %}'
  45. ),
  46. }
  47. ), 'django.template.loaders.filesystem.Loader'],
  48. )
  49. template = engine.get_template('one.html')
  50. output = template.render(Context({}))
  51. self.assertEqual(output.strip(), 'three locmem-three two locmem-two one locmem-one')
  52. def test_extend_self_error(self):
  53. """
  54. Catch if a template extends itself and no other matching
  55. templates are found.
  56. """
  57. engine = Engine(dirs=[os.path.join(RECURSIVE, 'fs')])
  58. template = engine.get_template('self.html')
  59. with self.assertRaises(TemplateDoesNotExist):
  60. template.render(Context({}))
  61. def test_extend_cached(self):
  62. engine = Engine(
  63. dirs=[
  64. os.path.join(RECURSIVE, 'fs'),
  65. os.path.join(RECURSIVE, 'fs2'),
  66. os.path.join(RECURSIVE, 'fs3'),
  67. ],
  68. loaders=[
  69. ('django.template.loaders.cached.Loader', [
  70. 'django.template.loaders.filesystem.Loader',
  71. ]),
  72. ],
  73. )
  74. template = engine.get_template('recursive.html')
  75. output = template.render(Context({}))
  76. self.assertEqual(output.strip(), 'fs3/recursive fs2/recursive fs/recursive')
  77. cache = engine.template_loaders[0].get_template_cache
  78. self.assertEqual(len(cache), 3)
  79. expected_path = os.path.join('fs', 'recursive.html')
  80. self.assertTrue(cache['recursive.html'].origin.name.endswith(expected_path))
  81. # Render another path that uses the same templates from the cache
  82. template = engine.get_template('other-recursive.html')
  83. output = template.render(Context({}))
  84. self.assertEqual(output.strip(), 'fs3/recursive fs2/recursive fs/recursive')
  85. # Template objects should not be duplicated.
  86. self.assertEqual(len(cache), 4)
  87. expected_path = os.path.join('fs', 'other-recursive.html')
  88. self.assertTrue(cache['other-recursive.html'].origin.name.endswith(expected_path))
  89. def test_unique_history_per_loader(self):
  90. """
  91. Extending should continue even if two loaders return the same
  92. name for a template.
  93. """
  94. engine = Engine(
  95. loaders=[
  96. ['django.template.loaders.locmem.Loader', {
  97. 'base.html': '{% extends "base.html" %}{% block content %}{{ block.super }} loader1{% endblock %}',
  98. }],
  99. ['django.template.loaders.locmem.Loader', {
  100. 'base.html': '{% block content %}loader2{% endblock %}',
  101. }],
  102. ]
  103. )
  104. template = engine.get_template('base.html')
  105. output = template.render(Context({}))
  106. self.assertEqual(output.strip(), 'loader2 loader1')
  107. class NonRecursiveLoader(Loader):
  108. def __init__(self, engine, templates_dict):
  109. self.templates_dict = templates_dict
  110. super(NonRecursiveLoader, self).__init__(engine)
  111. def load_template_source(self, template_name, template_dirs=None):
  112. try:
  113. return self.templates_dict[template_name], template_name
  114. except KeyError:
  115. raise TemplateDoesNotExist(template_name)
  116. @ignore_warnings(category=RemovedInDjango20Warning)
  117. class NonRecursiveLoaderExtendsTests(SimpleTestCase):
  118. loaders = [
  119. ('template_tests.test_extends.NonRecursiveLoader', {
  120. 'base.html': 'base',
  121. 'index.html': '{% extends "base.html" %}',
  122. 'recursive.html': '{% extends "recursive.html" %}',
  123. 'other-recursive.html': '{% extends "recursive.html" %}',
  124. 'a.html': '{% extends "b.html" %}',
  125. 'b.html': '{% extends "a.html" %}',
  126. }),
  127. ]
  128. def test_extend(self):
  129. engine = Engine(loaders=self.loaders)
  130. output = engine.render_to_string('index.html')
  131. self.assertEqual(output, 'base')
  132. def test_extend_cached(self):
  133. engine = Engine(loaders=[
  134. ('django.template.loaders.cached.Loader', self.loaders),
  135. ])
  136. output = engine.render_to_string('index.html')
  137. self.assertEqual(output, 'base')
  138. cache = engine.template_loaders[0].template_cache
  139. self.assertIn('base.html', cache)
  140. self.assertIn('index.html', cache)
  141. # Render a second time from cache
  142. output = engine.render_to_string('index.html')
  143. self.assertEqual(output, 'base')
  144. def test_extend_error(self):
  145. engine = Engine(loaders=self.loaders)
  146. msg = 'Cannot extend templates recursively when using non-recursive template loaders'
  147. with self.assertRaisesMessage(ExtendsError, msg):
  148. engine.render_to_string('recursive.html')
  149. with self.assertRaisesMessage(ExtendsError, msg):
  150. engine.render_to_string('other-recursive.html')
  151. with self.assertRaisesMessage(ExtendsError, msg):
  152. engine.render_to_string('a.html')