Python HTML template ternary operator - python

I've come across with different python ternary operators such as:
a if b else 0
but it didn't work when I tried to include it inside Django HTML template
{% a if b else 0 %}
Here is the exact code that I'll be using but won't work:
{% 'error' if form.title.errors else '' %}
or
{% form.title.errors ? 'error' : '' %}
I don't like to do the usual
{% if form.title.errors %}error{% endif %}
because it looks bulky in my opinion especially if I add an else statement.
Any suggestions? or should I just stick with it?

You can get more or less the behavior you want by using the yesno filter (documentation):
{{ form.title.errors|yesno:"errors," }}

In Django, the templatetags just support {% if %}{% else %}{% endif %}. If you don't want to use:
{% if form.title.errors %}error{% endif %}
You can try:
{{ error|default:'' }}
And the test in django template is bellow:
...from django.template import Context, Template
...from django.conf import settings
...settings.configure()
...t = Template("My name is: {{ name|default:'anonymous' }} ")
If default:
...t.render(Context({}))
it will return:
'My name is anonymous '
If has name:
...t.render(Context({"name": "John"}))
result:
'My name is John '
Read more: https://docs.djangoproject.com/en/1.9/ref/templates/

Related

Check if key exists in a Python dict in Jinja2 templates

I have a python dictionary:
settings = {
"foo" : "baz",
"hello" : "world"
}
This variable settings is then available in the Jinja2 template.
I want to check if a key myProperty exists in the settings dict within my template, and if so take some action:
{% if settings.hasKey(myProperty) %}
takeSomeAction();
{% endif %}
What is the equivalent of hasKey that I can use?
Like Mihai and karelv have noted, this works:
{% if 'blabla' in item %}
...
{% endif %}
I get a 'dict object' has no attribute 'blabla' if I use {% if item.blabla %} and item does not contain a blabla key
You can test for key definition this way:
{% if settings.property is defined %}
#...
{% endif %}
This works fine doesn't work in cases involving dictionaries. In those cases, please see the answer by tshalif.
Otherwise, with SaltStack (for example), you will get this error:
Unable to manage file: Jinja variable 'dict object' has no attribute '[attributeName]'
if you use this approach:
{% if settings.myProperty %}
note:
Will also skip, if settings.myProperty exists, but is evaluated as False (e.g. settings.myProperty = 0).
Actually, in the style of Python, if you do a simple if statement, it will work:
{% if settings.foo %}
Setting Foo: {{ settings.foo }}
{% endif %}
{% if settings.bar %}
Setting Bar: {{ settings.bar }}
{% endif %}
{% if settings.hello %}
Setting Hello: {{ settings.hello }}
{% endif %}
Output:
Setting Foo: baz
Setting Hello: world
Cheers!

How to dynamically add items to jinja variable in Flask?

I'm building a website using Flask with its jinja2 templating engine and I'm dynamically building the menu (as described here):
{%
set navigation_bar = [
('/', 'index', 'Home'),
('/aboutus/', 'aboutus', 'About Us'),
('/faq/', 'faq', 'FAQ')
]
%}
{% set active_page = active_page|default('index') -%}
<ul>
{% for href, id, title in navigation_bar %}
<li{% if id == active_page %} class="active"{% endif %}>
{{ title|e }}
</li>
{% endfor %}
</ul>
Now if a user is logged in I want to show some additional things. So at runtime I want to add items to the navigation_bar variable. I tried something like this:
{% if g.user.is_authenticated() %}
{% navigation_bar.append(('/someotherpage', 'someotherpage', 'SomeOtherPage')) -%}
{% endif %}
But unfortunately this results in the following error: TemplateSyntaxError: Encountered unknown tag 'navigation_bar'. Jinja was looking for the following tags: 'endblock'. The innermost block that needs to be closed is 'block'.
So: does anybody know how I can add additional items to a jinja2 variable at runtime? All tips are welcome!
[bonus question]
I was also wondering, what does the - do at the end of {% set active_page = active_page|default('index') -%}?
The error occurs because Jinja can't identify block. Each Jinja block should start from block name. do block from do extension meets your needs. To use it you should add
do extension to jinja extensions. You can do this like so:
app.jinja_env.add_extension('jinja2.ext.do')
And then you can use do extension. Your example should looks like this:
{% if g.user.is_authenticated() %}
{% do navigation_bar.append(('/someotherpage', 'someotherpage', 'SomeOtherPage')) %}
{% endif %}
Here's another simple example.
You will find answer to your bonus question here. In short - removes whitespaces from start or end of block (this depends on where it is located).
To complete the answer of Slava Bacherikov, if you don't have the Jinja "do extension", you can use the tag set:
{% if g.user.is_authenticated() %}
{# use a dummy variable name, we juste need the side-effect of method call #}
{% set _z = navigation_bar.append(('/someotherpage', 'someotherpage', 'SomeOtherPage')) %}
{% endif %}

Use `With` Tag to invert a boolean in Django Template?

I want to pass a value to an include tag that is the OPPOSITE of a variable passed in.
This is what I tried (basically):
{% with s_options as not disp %}
{% include "e.html" with show_options=s_options only %}
{% endwith %}
Is there any way to do what I want?
Not sure if this is the best solution, but I just made a new filter:
from django import template
register = template.Library()
#register.filter(name="not_value")
def not_value(true_value):
return not true_value
And then did:
{% load not_value %}
{% with s_options=disp|not_value %} {# WILL NOT WORK WITH "as" #}
{% include "e.html" with show_options=s_options only %}
{% endwith %}
Note that, possibly, this might work as well (though I have not tried):
{% include "e.html" with show_options=s_options|not_value only %}
This is a bit of a hack using the built in filter yesno, but it works:
{% with reversed_value=original_value|yesno:',True' %}
{# Do something #}
{% endwith %}
Note the comma before 'True'. The way it works is that yesno will return an empty string if the original value is True, which will evaluate as False if you're doing any boolean operations on it.

flask and wtf - how can I direct tag attributes for fields?

After fiddling with wtforms, fields use widgets to actually render them to html. I wrote some custom field/widget to draw html in a way that I'd more like to. But here's a question:
suppose I want to render them with pre-defined css class or give actual details myself.
How can I achieve this? and on what phase of handling requests(at Form class declaration? or when setting attributes to give Form some Fields? or when I'm actually calling them in jinja2 templates) I should do that?
I use a Jinja macro something like this:
{% macro field_with_errors(field) %}
{% set css_class=kwargs.pop('class', '') %}
{% if field.type in ('DateField', 'DateTimeField') %}
{{ field(class='date ' + css_class, **kwargs) }}
{% elif field.type == 'IntegerField' %}
{{ field(class='number ' + css_class, **kwargs) }}
{% else %}
{{ field(class=css_class, **kwargs) }}
{% endif %}
{% if field.errors %}
<ul class="errors">{% for error in field.errors %}<li>{{ error|e }}</li>{% endfor %}</ul>
{% endif %}
{% endmacro %}
usage is something like:
{{ field_with_errors(form.foo, placeholder='bar') }}
This lets me avoid boilerplate, but also lets me keep the display decisions in the template space.
Have a look at the rendering fields section.
Alternatively, you can add attributes to be rendered in the Jinja2 (etc.) template:
<div class="input-prepend">
{{ form.address(placeholder="example.com", id="address", autofocus="autofocus", required="required") }}
</div>
There's nothing to prevent you from using a variable for the ID value above, instead of address, then rendering the template with a keyword argument to populate it.

How do I do parsing in Django templates?

post = { sizes: [ { w:100, title="hello"}, {w:200, title="bye"} ] }
Suppose I pass that to my Django templates. Now, I want to display the title where width = 200. How can I do that, without doing it the brute-force way:
{{ post.sizes.1.title }}
I want to do it the parsed way.
A neat way to do it is with a filter template tag.
from django.template import Library
register = Library()
#register.filter('titleofwidth')
def titleofwidth(post, width):
"""
Get the title of a given width of a post.
Sample usage: {{ post|titleofwidth:200 }}
"""
for i in post['sizes']:
if i['w'] == width:
return i['title']
return None
That should go in a templatetags package, say as postfilters.py, and {% load postfilters %} in your template.
Naturally you could also alter this to give you the correct sizes object and so you could do {% with post|detailsofwidth:200 as postdetails %}{{ postdetails.something }}, {{ postdetails.title }}{% endwith %}.
{% for i in post.sizes %}
{% if i.w == 200 %}{{ i.title }}{% endif %}
{% endfor %}

Categories