28

If I return a Jinja2 template like so: return render_response('home.htm', **context)

How do then get a list of the variables in context from within the template?

Christian
  • 1,126
  • 2
  • 11
  • 15

3 Answers3

38

Technically, because context is not passed as a named dictionary, a little work is required to generate a list of the context variables from inside a template. It is possible though.

  1. Define a Jinja context function to return the jinja2.Context object, which is essentially a dictionary of the global variables/functions

  2. Make that function available in the global namespace; i.e. a jinja2.Environment or jinja2.Template globals dictionary

  3. Optionally, filter objects from the context; for instance, use callable() to skip Jinja's default global helper functions (range, joiner, etc.). This may be done in the context function or the template; wherever it makes the most sense.

Example:

>>> import jinja2
>>> 
>>> @jinja2.contextfunction
... def get_context(c):
...         return c
... 
>>> tmpl = """ 
... {% for key, value in context().items() %}
...     {% if not callable(value) %}
...         {{ key }}:{{ value }}
...     {% endif %}
... {% endfor %}
... """
>>> 
>>> template = jinja2.Template(tmpl)
>>> template.globals['context'] = get_context
>>> template.globals['callable'] = callable
>>>
>>> context = {'a': 1, 'b': 2, 'c': 3}
>>> 
>>> print(template.render(**context))
        a:1
        c:3
        b:2

[Alternately, call render_response with ('home.htm', context=context) to make the other solution work.]

t-mart
  • 890
  • 11
  • 27
Garrett
  • 47,045
  • 6
  • 61
  • 50
  • 2
    Note that because of the `callable` check, your solution would disregard functions that have explicitly been passed as part of the context. Probably doesn't happen often, but could make a difference. – Daniel Werner Jun 21 '11 at 15:48
  • 1
    True. This simple solution can definitely be improved. For instance, if ``template`` is a global, ``get_context()`` can return a new dictionary based on ``context`` but without keys that also exist in ``template.globals``. – Garrett Jun 21 '11 at 16:17
  • 1
    Added a feature request to enable this by default https://github.com/mitsuhiko/jinja2/issues/174 – anatoly techtonik Jan 17 '13 at 07:34
  • @techtonik Any news? I struggle with exactly this – Pavel 'Strajk' Dolecek Oct 23 '14 at 18:06
  • @Strajk, I asked Armin, but not sure he has the time to look on that. For me the pull request with a screenshot would be more convincing than some code piece and some idea floating around. – anatoly techtonik Oct 24 '14 at 08:45
3

Here's how to get @crewbum's answer working from a Flask app:

import jinja2

@jinja2.contextfunction
def get_context(c):
    return c

app.jinja_env.globals['context'] = get_context
app.jinja_env.globals['callable'] = callable
Community
  • 1
  • 1
joemaller
  • 19,579
  • 7
  • 67
  • 84
1

I found @Garrett's answer to be a bit more complex than what I wanted. I found that I can easily inspect the context by adding a clone of the context to the context itself:

contextCopy = dict(context)
context['all'] = contextCopy

And then pretty printing that into my Jinja template with <pre>{{ all|pprint }}</pre>.

Jo Sprague
  • 16,523
  • 10
  • 42
  • 62