callables.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. from django import template
  2. from django.utils.unittest import TestCase
  3. class CallableVariablesTests(TestCase):
  4. def test_callable(self):
  5. class Doodad(object):
  6. def __init__(self, value):
  7. self.num_calls = 0
  8. self.value = value
  9. def __call__(self):
  10. self.num_calls += 1
  11. return {"the_value": self.value}
  12. my_doodad = Doodad(42)
  13. c = template.Context({"my_doodad": my_doodad})
  14. # We can't access ``my_doodad.value`` in the template, because
  15. # ``my_doodad.__call__`` will be invoked first, yielding a dictionary
  16. # without a key ``value``.
  17. t = template.Template('{{ my_doodad.value }}')
  18. self.assertEqual(t.render(c), u'')
  19. # We can confirm that the doodad has been called
  20. self.assertEqual(my_doodad.num_calls, 1)
  21. # But we can access keys on the dict that's returned
  22. # by ``__call__``, instead.
  23. t = template.Template('{{ my_doodad.the_value }}')
  24. self.assertEqual(t.render(c), u'42')
  25. self.assertEqual(my_doodad.num_calls, 2)
  26. def test_alters_data(self):
  27. class Doodad(object):
  28. alters_data = True
  29. def __init__(self, value):
  30. self.num_calls = 0
  31. self.value = value
  32. def __call__(self):
  33. self.num_calls += 1
  34. return {"the_value": self.value}
  35. my_doodad = Doodad(42)
  36. c = template.Context({"my_doodad": my_doodad})
  37. # Since ``my_doodad.alters_data`` is True, the template system will not
  38. # try to call our doodad but will use TEMPLATE_STRING_IF_INVALID
  39. t = template.Template('{{ my_doodad.value }}')
  40. self.assertEqual(t.render(c), u'')
  41. t = template.Template('{{ my_doodad.the_value }}')
  42. self.assertEqual(t.render(c), u'')
  43. # Double-check that the object was really never called during the
  44. # template rendering.
  45. self.assertEqual(my_doodad.num_calls, 0)
  46. def test_do_not_call(self):
  47. class Doodad(object):
  48. do_not_call_in_templates = True
  49. def __init__(self, value):
  50. self.num_calls = 0
  51. self.value = value
  52. def __call__(self):
  53. self.num_calls += 1
  54. return {"the_value": self.value}
  55. my_doodad = Doodad(42)
  56. c = template.Context({"my_doodad": my_doodad})
  57. # Since ``my_doodad.do_not_call_in_templates`` is True, the template
  58. # system will not try to call our doodad. We can access its attributes
  59. # as normal, and we don't have access to the dict that it returns when
  60. # called.
  61. t = template.Template('{{ my_doodad.value }}')
  62. self.assertEqual(t.render(c), u'42')
  63. t = template.Template('{{ my_doodad.the_value }}')
  64. self.assertEqual(t.render(c), u'')
  65. # Double-check that the object was really never called during the
  66. # template rendering.
  67. self.assertEqual(my_doodad.num_calls, 0)
  68. def test_do_not_call_and_alters_data(self):
  69. # If we combine ``alters_data`` and ``do_not_call_in_templates``, the
  70. # ``alters_data`` attribute will not make any difference in the
  71. # template system's behavior.
  72. class Doodad(object):
  73. do_not_call_in_templates = True
  74. alters_data = True
  75. def __init__(self, value):
  76. self.num_calls = 0
  77. self.value = value
  78. def __call__(self):
  79. self.num_calls += 1
  80. return {"the_value": self.value}
  81. my_doodad = Doodad(42)
  82. c = template.Context({"my_doodad": my_doodad})
  83. t = template.Template('{{ my_doodad.value }}')
  84. self.assertEqual(t.render(c), u'42')
  85. t = template.Template('{{ my_doodad.the_value }}')
  86. self.assertEqual(t.render(c), u'')
  87. # Double-check that the object was really never called during the
  88. # template rendering.
  89. self.assertEqual(my_doodad.num_calls, 0)