How to detect debug mode in jinja? - python

Under flask, I want to include/exclude stuff in the jinja template based upon whether, or not, we are in debug mode. I'm not debating if this is a good, or bad, idea (i'd vote 'bad' but want to do it just for this case nonetheless :-), so how might this best happen?
I was hoping i would not have to pass the variable explicitly into the template, unlike this:
render_template('foo.html', debug=app.debug)
not that this would be too hard, but I'd rather just magically say in the template:
{% if debug %}
go crazzzzy
{% endif %}
Is there some default variable just lazing about waiting for me to pounce?

use context processors
To inject new variables automatically into the context of a template, context processors exist in Flask. Context processors run before the template is rendered and have the ability to inject new values into the template context. A context processor is a function that returns a dictionary. The keys and values of this dictionary are then merged with the template context, for all templates in the app:
#app.context_processor
def inject_debug():
return dict(debug=app.debug)
now debug variable accessible in templates.

When you run your flask application with app.run(debug=True), you can also just check the config object like so:
{% if config['DEBUG'] %}
<h1>My html here</h1>
{% endif %}

Related

How to set a variable from within a template

My layout template contains a header and I'd like to add a CSS class to the currently selected menu option.
class="active"
I thought I found the solution here but I'm still having issues. When I paste the following code into my template I get a server error.
{% rule = request.url_rule %}
Why didn't this work? How can I set a variable to control the menu in the templates?
{% rule = request.url_rule %} is not valid syntax in Jinja. If you want to set a context variable from a template, use set:
{% set rule = request.rule %}
request is already passed to each template context automatically, you don't need to pass it in render_template.
My best guess would be that the request object isn't getting passed to the template. If it isn't being passed you wouldn't be able to access it when rendering the template. You could pass it explicitly, which would look something like this:
from flask import request
from flask import render_template
#app.route('/hello/')
def hello():
return render_template('hello.html', request=request)
Someone commented that swankswashbucklers answer wouldn't fix my problem so I'm posting my solution which was inspired by his suggestion.
I simply manually set a variable called title when creating the view.
def home():
return render_template(
'index.html',
title='Home',
)
Within the template I referenced the variable to decide which menu item to highlight.
{% if title == "Home" %}
<li class="active">
{% else %}
<li>
{% endif %}
It turned out in my situation I didn't need to access the current url.

Flask - SubViews

I am looking to use a certain design pattern in my application, but I am not sure if my pattern really even fits with Flask mechanisms. I am just verifying that I have not overlooked existing solutions.
I would like to have a top-level View that renders the response of another proxied request. The thing is, I am not proxying external URLs, but rather views from within my same application (kind of like Blueprints that depend on other Blueprints). Similar to the 'render_template()' function, I am looking for something like render_view, or even better, *request_view_as_string*. I then need to process the response and re-render.
I am using template inheritance to the best of my abilities (jinja2), but much of my difficulty is coming from lots of non-template processing in between the template blocks. I am still getting a feel for jinja, and my templates are starting to feel polluted with hacks.
Edit
Basically, I misunderstood the role of jinja. My application needs to build heavier on jinja. I kept trying to get in and out of jinja as quickly as possible, and that is where my nested dependencies were starting to cause problems. Ultimately, most of the features I needed for my "subviews" was built right into Jinja, I just wasn't sure how to properly integrate them with FLask.
First off, Jinja2 supports macros, which let you share functionality between templates:
{# helpers.jinja #}
{% macro generate_select(itrbl) %}
<select{{kwargs|xmlattrs}}>
{% for item in itrbl %}
<option value="{{item.value}}">{{item.text}}</option>
{% endfor %}
</select>
{% endmacro %}
{# page1.jinja #}
{% import "helpers.jinja" as helpers %}
{{ helpers.generate_select(data, name="my_data_field") }}
For more complicated bits of functionality (A / B testing, loading different features depending on what the user's account has enabled, etc.) extends, include, and import can take variable values:
{# A custom template with a *lot* of hooks #}
{% extends base_template %}
{% import custom_functionality_provider as provider %}
{% block common_name %}
{% if features.feature_x %}
{% include feature_x_include %}
{% endif %}
{{ provider.operation() }}
{% endblock common_name %}
#app.route("/some-route")
def some_route():
# Of course, in real life you would determine these values
# on the basis of user / condition lookups, rather than
# hardcoding values in your render_template call
render_template("custom.jinja", base_template="AB/A/base.jinja",
custom_functionality_provider="macros/lowcostplan.jinja",
feature_x_include="AB/A/features/feature_x.jinja",
features=some_features_object)
Finally, you can pass callables that return strings to any Jinja template, giving you access to the full power of Python:
def custom_implimentation_a(**context_args):
return render_template("template_a.jinja", **context_args)
def custom_implimentation_b(**context_args):
return render_template("template_b.jinja", **context_args)
#app.route("/some-route")
def some_route():
if condition:
provider = custom_implimentation_a # Note, no parenthesis
else:
provider = custom_implimentation_b
return render_template("some_page.jinja", provider=provider)
I do consider Sean's first answer as the most appropriate, but I did run across this little mechanism for those times when Jinja is making Python tasks a bit difficult.
http://werkzeug.pocoo.org/docs/local/
This should be a little more productive than Flask's g variable. See also a slightly different usage (when one global 'namespace' is no longer manageable)
http://flask.pocoo.org/snippets/13/
I very often forget that Flask and Werkzeug are related projects. The huge benefit of this is that much of their functionality does not overlap with the other project.
When you are newbie approaching from the Flask side, if you feel like Flask is missing a few gears, there is a good chance its because they already included them in Werkzeug.

django : get the current locale inside a templatetag

I've an internationalized django (1.4) app.
In this app, I have a templatetag which needs to know what is the current language.
I think I could use django.utils.translation.get_language but it seems that inside the templatetag, it returns the default language and not the current language.
I fixed it by reading request.LANGUAGE_CODE from context.
But I would like to know if there is a better way to get the language in a templatetag
There's a few default templatetags you can use
{% get_current_language %}
or
{% get_current_language as FOO %}
e.g.
{% render_bar request FOO %}

Django template check for empty when I have an if inside a for

I have the following code in my template:
{% for req in user.requests_made_set.all %}
{% if not req.is_published %}
{{ req }}
{% endif %}
{% empty %}
No requests
{% endfor %}
If there are some requests but none has the is_published = True then how could I output a message (like "No requests") ?? I'd only like to use Django templates and not do it in my view!
Thanks
Even if this might be possible to achieve in the template, I (and probably many other people) would advise against it. To achieve this, you basically need to find out whether there are any objects in the database matching some criteria. That is certainly not something that belongs into a template.
Templates are intended to be used to define how stuff is displayed. The task you're solving is determining what stuff to display. This definitely belongs in a view and not a template.
If you want to avoid placing it in a view just because you want the information to appear on each page, regardless of the view, consider using a context processor which would add the required information to your template context automatically, or writing a template tag that would solve this for you.

In Jinja2 whats the easiest way to set all the keys to be the values of a dictionary?

I've got a dashboard that namespaces the context for each dashboard item. Is there a quick way I can set all the values of a dictionary to the keys in a template?
I want to reuse templates and not always namespace my variables.
My context can be simplified to look something like this:
{
"business": {"businesses": [], "new_promotions": []},
"messages": {"one_to_one": [], "announcements": []
}
So in a with statement I want to set all the business items to be local for the including. To do this currently I have to set each variable individually:
{% with %}
{% set businesses = business["businesses"] %}
{% set new_promotions = business["new_promotions"] %}
{% include "businesses.html" %}
{% endwith %}
I tried:
{% with %}
{% for key, value in my_dict %}
{% set key = value %}
{% endfor %}
{% include "businesses.html" %}
{% endwith %}
But they only have scope in the for loop so aren't scoped in the include...
Long story short: you can't set arbitrary variables in the context. The {% set key = value %} is just setting the variable named key to the given value.
The reason is because Jinja2 compiles templates down to Python code. (If you want to see the code your template generates, download the script at http://ryshcate.leafstorm.us/paste/71c95831ca0f1d5 and pass it your template's filename.) In order to make processing faster, it creates local variables for every variable you use in the template (only looking up the variable in the context the first time it's encountered), as opposed to Django, which uses the context for all variable lookups.
In order to generate this code properly, it needs to be able to track which local or global variables exist at any given time, so it knows when to look up in the context. And setting random variables would prevent this from working, which is why contextfunctions are not allowed to modify the context, just view it.
What I would do, though, is instead of having your business-displaying code be an included template, is have it be a macro in another template. For example, in businesses.html:
{% macro show_businesses(businesses, new_promotions) %}
{# whatever you're displaying... #}
{% endmacro %}
And then in your main template:
{% from "businesses.html" import show_businesses %}
{% show_businesses(**businesses) %}
Or, better yet, separate them into two separate macros - one for businesses, and one for new promotions. You can see a lot of cool template tricks at http://bitbucket.org/plurk/solace/src/tip/solace/templates/, and of course check the Jinja2 documentation at http://jinja.pocoo.org/2/documentation/templates.
I've found a work around - by creating a context function I can render the template and directly set the context or merge the context (not sure thats good practise though).
#jinja2.contextfunction
def render(context, template_name, extra_context, merge=False):
template = jinja_env.get_template(template_name)
# Merge or standalone context?
if merge:
ctx = context.items()
ctx.update(extra_context)
else:
ctx = extra_context
return jinja2.Markup(template.render(ctx))
So my templates look like:
{{ render("businesses.html", business) }}

Categories

Resources