sa125
sa125

Reputation: 28971

How can a custom jinja2 tag interface with the context of a flask request

I'm writing a custom jinja2 extension to use in flask applications and I'm looking for a way to access the templates context data using the tag I'm implementing. That is, I want the extension tag to use context params passed into the template:

@app.route('/users/<user_id>')
def user_page(user_id):
    ...
    return render_template('users/index.html', user_id=user_id, active=True)

The template:

<!-- I want this tag to see the value of user_id and active -->
{% my_jinja2_tag %}

I know I can render the context variable using {{ user_id }}, but what I'm looking for is a way to inspect the context of the template rendering a custom jinja2 extension. Is that doable? thanks.

Upvotes: 3

Views: 1672

Answers (1)

Augiwan
Augiwan

Reputation: 2482

ContextReference

Yes, it's possible using jinja2.nodes.ContextReference(). See the API reference here.

Relax, I'm going to guide you through it. :)

First the extension:

class ActiveCheckerExtension(jinja2.ext.Extension):
    """
    This will give us a {% check_active %} tag.
    """

    template = 'Active is : %s'
    tags = set(['check_active'])

    def _render_tag(self, context, caller):
        return jinja2.Markup(self.template % unicode(context['active']))

    def parse(self, parser):
        ctx_ref = jinja2.nodes.ContextReference()
        lineno = next(parser.stream).lineno
        node = self.call_method('_render_tag', [ctx_ref], lineno=lineno)
        return jinja2.nodes.CallBlock(node, [], [], [], lineno=lineno)

Then let's add it to Flask's jinja2.

app.jinja_env.add_extension(ActiveCheckerExtension)

Now in your template, you can do:

{% check_active %}

Make sure active is defined in all the templates you add the tag to, or else you'll get a KeyError because the context won't have that template variable.

Upvotes: 3

Related Questions