Skip to content

Commit

Permalink
Fixed #34883 -- Allowed template tags to set extra data on templates.
Browse files Browse the repository at this point in the history
By setting a value in the `parser.extra_data` mapping, template tags
pass additional data out of the parsing context.

Any extra data set is exposed on the template via the matching
`.extra_data` attribute.

Library authors should use a key to namespace extra data. The 'django'
namespace is reserved for internal use.
  • Loading branch information
carltongibson authored and felixxm committed Oct 2, 2023
1 parent f4e72e6 commit 35bbb2c
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 2 deletions.
10 changes: 9 additions & 1 deletion django/template/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,9 @@ def compile_nodelist(self):
)

try:
return parser.parse()
nodelist = parser.parse()
self.extra_data = parser.extra_data
return nodelist
except Exception as e:
if self.engine.debug:
e.template_debug = self.get_exception_info(e, e.token)
Expand Down Expand Up @@ -439,6 +441,12 @@ def __init__(self, tokens, libraries=None, builtins=None, origin=None):
self.filters = {}
self.command_stack = []

# Custom template tags may store additional data on the parser that
# will be made available on the template instance. Library authors
# should use a key to namespace any added data. The 'django' namespace
# is reserved for internal use.
self.extra_data = {}

if libraries is None:
libraries = {}
if builtins is None:
Expand Down
4 changes: 3 additions & 1 deletion docs/releases/5.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@ Signals
Templates
~~~~~~~~~

* ...
* Custom tags may now set extra data on the ``Parser`` object that will later
be made available on the ``Template`` instance. Such data may be used, for
example, by the template loader, or other template clients.

Tests
~~~~~
Expand Down
7 changes: 7 additions & 0 deletions tests/template_tests/templatetags/custom.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django import template
from django.template.base import TextNode
from django.template.defaultfilters import stringfilter
from django.utils.html import escape, format_html
from django.utils.safestring import mark_safe
Expand Down Expand Up @@ -216,3 +217,9 @@ def render(self, context):
count = self.count
self.count = count + 1
return str(count)


@register.tag("extra_data")
def do_extra_data(parser, token):
parser.extra_data["extra_data"] = "CUSTOM_DATA"
return TextNode("")
9 changes: 9 additions & 0 deletions tests/template_tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,15 @@ def test_compile_tag_error_27956(self):
if self.debug_engine:
self.assertEqual(e.exception.template_debug["during"], "{% badtag %}")

def test_compile_tag_extra_data(self):
"""Custom tags can pass extra data back to template."""
engine = self._engine(
app_dirs=True,
libraries={"custom": "template_tests.templatetags.custom"},
)
t = engine.from_string("{% load custom %}{% extra_data %}")
self.assertEqual(t.extra_data["extra_data"], "CUSTOM_DATA")

def test_render_tag_error_in_extended_block(self):
"""Errors in extended block are displayed correctly."""
e = self._engine(app_dirs=True)
Expand Down

0 comments on commit 35bbb2c

Please sign in to comment.