Scope of variables in template blocks
The Django documentation gives explicit details on how you can set a variable in the context using a custom template tag.
- class CurrentTimeNode3(template.Node):
- def __init__(self, format_string, var_name):
- self.format_string = format_string
- self.var_name = var_name
- def render(self, context):
- context[self.var_name] = datetime.datetime.now().strftime(self.format_string)
- return ''
Where can I use that variable?
Of course you can use in the template, but the scope depends on the templates structure. Let's take as example a template like this:
- {% extends 'site_base.html' %}
-
- {% load my_custom_tags %}
-
- {% block head %}
- {% get_current_time "%Y-%M-%d %I:%M %p" as my_current_time %}
- The current time is {{ my_current_time }}.
- {% endblock %}
This will have the expected output, in the head block of the site_base.html template will display the time.
The exception raises when you have multiple blocks where you want to use that variable:
- {% extends 'site_base.html' %}
-
- {% load my_custom_tags %}
-
- {% block head %}
- {% get_current_time "%Y-%M-%d %I:%M %p" as my_current_time %}
- The current time is {{ my_current_time }}.
- {% endblock %}
-
- {% block content %}
- The current time is {{ my_current_time }}.
- {% endblock %}
This usage will not display the time in the content block or if you set a list that you will iterate over, it will raise Caught an exception while rendering: Failed lookup for key [list] in u'[{\'block\': ...
Why is it a problem to call the template tag in both blocks?
Imagine you are doing some queries in that custom template tag, calling it in multiple blocks, increases your queries/page stat.
Why can't I use the variable in any block, since it is set in the context?
{% block %} pushes a new dictionary on the Context stack and pops it off when it reaches the matching {% endblock %}. This means any context value created while in the block has essentially gone out of scope on block exit.
Any solution?
A minor adjustment to set the variable in the main context
- def render(self, context):
- context.dicts[0][self.var_name] = datetime.datetime.now().strftime(self.format_string)
- return ''
Category: Django



Discussion
How about using the custom tag outside any template block?
Stefan, the django book says that "Any text outside of {% block %} tags in child templates will not be rendered.", it will not enter the Nodes render function.
Have you tested it?
I tested like this:
1. in site_base.html i used it to instantiate the variable (outside of a block), it was accessible in the child template in any block
2. in the child template instantiate it outside of a block, the render function is not called.
you just saved my life
Nice post! Well written, easy to follow, concise and really useful for me. Thanks!
Leave a Comment :
Leave a Comment