Home » Odeon Blogs » Liviu, Agile Bear »

Scope of variables in template blocks

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.

  1. class CurrentTimeNode3(template.Node):
  2. def __init__(self, format_string, var_name):
  3. self.format_string = format_string
  4. self.var_name = var_name
  5. def render(self, context):
  6. context[self.var_name] = datetime.datetime.now().strftime(self.format_string)
  7. 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:

  1. {% extends 'site_base.html' %}
  2. {% load my_custom_tags %}
  3. {% block head %}
  4. {% get_current_time "%Y-%M-%d %I:%M %p" as my_current_time %}
  5. The current time is {{ my_current_time }}.
  6. {% 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:

  1. {% extends 'site_base.html' %}
  2. {% load my_custom_tags %}
  3. {% block head %}
  4. {% get_current_time "%Y-%M-%d %I:%M %p" as my_current_time %}
  5. The current time is {{ my_current_time }}.
  6. {% endblock %}
  7. {% block content %}
  8. The current time is {{ my_current_time }}.
  9. {% 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

  1. def render(self, context):
  2. context.dicts[0][self.var_name] = datetime.datetime.now().strftime(self.format_string)
  3. return ''


Category: Django

Discussion

  1. How about using the custom tag outside any template block?


  2. 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.


  3. Have you tested it?


  4. 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.


  5. JoeZ99 on Nov 22, 2010 - 14:42 said:

    you just saved my life


  6. Luis on Apr 18, 2011 - 13:50 said:

    Nice post! Well written, easy to follow, concise and really useful for me. Thanks!




Leave a Comment :

(required)


(required)




(required)




(required)






Leave a Comment


Page generated in: 0.22s