I am beginner in computer science and trying to use python flask framework to create a webserver.
In the tutorials, I have seen the below jinja usage in the HTML which are
{% set a = somefunction() %}
{% with a = somefunction() %}
May I know what are the differences? Thanks.
While you may use {% set %} to define a variable, the {% with %} statement additionally creates a new scope which can be ended using the {% endwith %} statement.
For example:
{% with myvar=1 %}
...
{% endwith %}
myvar will only be available before the corresponding endwith.
You can also use with to create a local scope:
{% with %}
{% set myvar=1 %}
...
{% endwith %}
myvar will only be available within the given scope.
You can find information about these statements here (the examples shown here were taken from there also).
Variables inside a {% with %} statement are restricted to that particular statement, while variables created via {% set %} are accessible from anywhere in the template (they are global).
>>> import jinja2
>>> t = jinja2.Template("{% set a = 'Global' %}{% with a = 'Local' %}{{ 'First a is ' + a +'\n' }}{% endwith %}{{ 'Second a is ' + a }}")
>>> print(t.render())
First a is Local
Second a is Global
Related
Are variables set in Jekyll {% include %} files global in scope? That is, do they leak into the page that included then and subsequent includes?
For example, I have an include file with the following contents:
{% assign ai__attributes = "" %}
{% if include.width %}
{% capture ai__attributes %}{{ ai__attributes }}width="{{include.width}}" {% endcapture %}
{% endif %}
{% if ai__attributes != "" %}
{% capture ai__ial %}{:{{ai__attributes}}}{% endcapture %}
{% endif %}
![{{include.alt | default image }}]({{assetpath}}/{{include.path}}){{ai__ial}}
This sets teh ai__ial variable if include.width has been set. If I call this once with width set, and then again with it inset, will the ai__ial from the first call leak into the second? Is there any way to avoid this, e.g., by scoping the variable?
No way to set a local variable, but you can reset ai__ial in your include.
{% assign ai__attributes = "" %}
{% assign ai__ial = "" %}
...
When searching an array for a match in a Liquid template, how do you call contains exactly? For example, if tag of a page may contain separable or non-separable, how do you find the pages that contain only the separable and not the non-separable tag? In my experience, the {% if post.tags contains 'separable' %} statement considers both cases.
Refer to the documentation you can use this filter
{% assign tags = post.tags | where:"tag","separable" %}
Loop through the array and check the values with a match operator. If it matches change a variable from false to true:
{% assign found_seperable = false %}
{% for tag in post.tags %}
{% if tag == 'separable' %}
{% assign found_seperable = true %}
{% endif %}
{% endfor %}
Then check the variable:
{% if found_seperable %}
do what you want if true
{% else %}
do what you want if false
{% endif %}
I want to have one parent template and many children templates with their own variables that they pass to the parent, like so:
parent.html:
{% block variables %}
{% endblock %}
{% if bool_var %}
{{ option_a }}
{% else %}
{{ option_b }}
{% endif %}
child.html:
{% extends "parent.html" %}
{% block variables %}
{% set bool_var = True %}
{% set option_a = 'Text specific to this child template' %}
{% set option_b = 'More text specific to this child template' %}
{% endblock %}
But the variables end up undefined in the parent.
Ah. Apparently they won't be defined when they are passed through blocks. The solution is to just remove the block tags and set it up like so:
parent.html:
{% if bool_var %}
{{ option_a }}
{% else %}
{{ option_b }}
{% endif %}
child.html:
{% extends "parent.html" %}
{% set bool_var = True %}
{% set option_a = 'Text specific to this child template' %}
{% set option_b = 'More text specific to this child template' %}
If Nathron's solution does not fix your problem, you can use a function in combination with a global python variable to pass a variable value.
Advantage: The variable's value will available in all templates. You can set the variable inside a block.
Disadvantage: More overhead.
This is what I did:
child.j2:
{{ set_my_var('new var value') }}
base.j2
{% set my_var = get_my_var() %}
python code
my_var = ''
def set_my_var(value):
global my_var
my_var = value
return '' # a function returning nothing will print a "none"
def get_my_var():
global my_var
return my_var
# make functions available inside jinja2
config = { 'set_my_var': set_my_var,
'get_my_var': get_my_var,
...
}
template = env.get_template('base.j2')
generated_code = template.render(config)
In some cases, you can avoid this 'parameter-passing' by creating another variant of the parent that adds/removes some block and extends it instead.
{% extends [condition]|yesno:'parent_1.html,parent_2.html' %}
Jekyll bootstrap includes the file _includes/JB/setup:
{% capture jbcache %}
<!--
- Dynamically set liquid variables for working with URLs/paths
-->
{% if site.JB.setup.provider == "custom" %}
{% include custom/setup %}
{% else %}
{% if site.safe and site.JB.BASE_PATH and site.JB.BASE_PATH != '' %}
{% assign BASE_PATH = site.JB.BASE_PATH %}
{% assign HOME_PATH = site.JB.BASE_PATH %}
{% else %}
{% assign BASE_PATH = nil %}
{% assign HOME_PATH = "/" %}
{% endif %}
{% if site.JB.ASSET_PATH %}
{% assign ASSET_PATH = site.JB.ASSET_PATH %}
{% else %}
{% capture ASSET_PATH %}{{ BASE_PATH }}/assets/themes/{{ page.theme.name }}{% endcapture %}
{% endif %}
{% endif %}
{% endcapture %}{% assign jbcache = nil %}
I understand that this 1) captures the text as a variable then 2) assigns it to nil immediately, effectively throwing it away. So what does this do?
Because you want the side-effects of rendering but don't want the rendered output. If you don't capture, the rendered content is output. But you don't actually want the output, so you throw it away when you're done. It's a slight hack.
So if you want to compute without outputting the result, capturing in a variable is a reasonable thing to do. The "then assign to nil" hack is a way of saying we are interested in the side-effects of the rendering computation, not the output. Those other assignments persist have effects that persist even when the variable is thrown out.
The {%include custom/setup %}'s output will similarly be thrown away, but its side-effects may be important.
I'd like to iterate over a set of objects and find the maximum of one particular attribute, however jinja2 ignores any action within an iterator on a variable declared outside of the iterator. For example:
{% set maximum = 1 %}
{% for datum in data %}
{% if datum.frequency > 1 %}
{% set maximum = datum.frequency %}
{% endif %}
{% endfor %}
{# maximum == 1 #}
datum.frequency is definitely greater than 1 for some datum in data.
EDIT (solution)
This is similar to this post, but there's a bit more to it. The following works and is very ugly.
{% set maximum = [1] %}
{% for datum in data %}
{% if datum.freq > maximum[-1] %}
{% if maximum.append( datum.freq ) %}{% endif %}
{% endif %}
{% endfor %}
{% set maximum = maximum[-1] %}
Have you considered writing a custom filter to return the highest value of a particular attribute within your collection? I prefer to minimize the amount of logic I use in Jinja2 templates as part of maintaining a 'separation of concerns'.
Here is a link to a very good example of how one can be written in python:
Custom jinja2 filter for iterator
Once you have your filter returning the value you need access it by using '|' like so:
{% set maximum = datum|filtername %}