Stringers
Stringers

Reputation: 125

Accessing flask methods in Jinaj2.Template.render()

Say we have a flask template as such:

{% extends "layout.html" %}

{% block body %}

<div class="container page-container">
{% with messages = get_flashed_messages() %}
  {% if messages %}
    <ul class=flashes>
    {% for message in messages %}
      <li>{{ message }}</li>
    {% endfor %}
    </ul>
  {% endif %}
{% endwith %}
</div>

{% endblock %}

We can render this template using the flask.render_template() function, and thus display a flash message using code like this:

from flask import flash, render_template

@timesheet_billing.route('/timesheet-billing')
def timesheet_billing_select_job():
    jobs = get_open_jobs()
    flash('A job was not selected!')
    return render_template('timesheet_billing/index.html', jobs = jobs) 

However if we render it using Jinja2's template class function jinja2.Template.render() with code like this:

from flask import flash
import jinja2

env = jinja2.Environment(loader=jinja2.PackageLoader('templates'))
index_temp = env.get_template('index.html')

@timesheet_billing.route('/timesheet-billing')
def timesheet_billing_select_job():
    jobs = get_open_jobs()
    flash('A job was not selected!')
    return index_temp.render(jobs = jobs)  

We get the following error when trying to load the page:

jinja2.exceptions.UndefinedError: 'get_flashed_messages' is undefined

What is the difference here? The answer in this question suggests that they should be the same. However it seems in one we do not have access to flask methods.

Upvotes: 0

Views: 766

Answers (1)

CamiEQ
CamiEQ

Reputation: 771

I believe the difference here is how flask.get_flashed_messages works. This webpage https://flask.palletsprojects.com/en/1.1.x/templating/ explains the scope of jinja2 context variables:

The Jinja Context Behavior:

These variables are added to the context of variables, they are not global variables. The difference is that by default these will not show up in the context of imported templates. This is partially caused by performance considerations, partially to keep things explicit.

Here is where flask's render_template makes a difference, when comparing it to jinja2.render (from the question link you referred to):

def render_template(template_name_or_list, **context):
    ctx = _app_ctx_stack.top
    ctx.app.update_template_context(context)
    return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list),
                   context, ctx.app)

def _render(template, context, app):   
    before_render_template.send(app, template=template, context=context)
    rv = template.render(context)
    template_rendered.send(app, template=template, context=context)
    return rv

by calling render directly, you're missing the application context update call, which will inject all the information a template context processor will need to make functions (like get_flashed_messages, in this case) available to templates.

Upvotes: 1

Related Questions