Skip to content

Instantly share code, notes, and snippets.

@gmocamilotd
Created September 24, 2019 15:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gmocamilotd/62d5424880824ee86bc800d64e3a3eca to your computer and use it in GitHub Desktop.
Save gmocamilotd/62d5424880824ee86bc800d64e3a3eca to your computer and use it in GitHub Desktop.
## Comparison operations
* {% if %} with {% elif %} {% else %}.-
The {% if %} statement is the primary building block to evaluate conditions. The {% if %} statement is typically used in conjunction with the {% elif %} and {% else %} statements to evaluate more than one condition. An {% if %} statement with an argument variable evaluates to true if a variable exists and is not empty or if the variable holds a True boolean value. Listing 4-14 illustrates a series of {% if %} statement examples.
```
{% if drinks %} {% if drinks %} {% if drinks %}
We have drinks! We have drinks We have drinks
{% endif %} {% else %} {% elif drinks_on_sale %}
No drinks,sorry We have drinks on sale!
{% endif %} {% else %}
No drinks, sorry
{% endif %}
```
* {% for %} and {% for %} with {% else %} - **Loops**
The {% for %} statement iterates over items on a dictionary, list, tuple or string variable.
The {% for %} statement also supports the {% else %} statement which is processed in case there are no iterations in a loop (i.e. the main variable is empty)
example:
```
<ul> <ul>
{% for drink in drinks %} {% for storeid,store in stores %}
<li>{{ drink.name }}</li> <li><a href="/stores/{{storeid}}/">{{store.name}}</a></li>
{% else %} {% endfor %}
<li>No drinks, sorry</li> </ul>
{% endfor %}
</ul>
```
The {% for %} statement also generates a series of variables to manage the iteration process, such as an iteration counter, a first iteration flag and a last iteration flag. The next table illustrates the {% for %} statement variables.
Variable| Description
-- | --
loop.index | The current iteration of the loop (1-indexed)
loop.index0| The current iteration of the loop (0-indexed)
loop.revindex |The number of iterations from the end of the loop (1-indexed)
loop.revindex0| The number of iterations from the end of the loop (0-indexed)
loop.first| True if it's the first time through the loop
loop.last| True if it's the last time through the loop
loop.length| The number of items in the sequence.
loop.cycle| A helper function to cycle between a list of sequences.
loop.depth| Indicates how deep in a recursive loop the rendering currently is, starts at level 1
loop.depth0 | Indicates how deep in a recursive loop the rendering currently is, starts at level 0
### Neste Jinja Loops: Use reference variable and cycle variable
On certain occasions you may need to nest multiple {% for %} statements and access parent loop items. In Django templates, this is easy because there's a variable for just this purpose. However, Jinja templates don't have this variable as you can see in table 4-1. A solution in Jinja templates is to define a reference variable with {% set %} before entering the child loop to gain access to the parent loop, as illustrated in the following snippet
```
<ul>
{% for chapter in chapters %}
{% set chapterloop = loop %}
{% for section in chapter %}
<li> {{chapterloop.index }}.{{ loop.index }}">{{ section }}</li>
{% endfor %}
{% endfor %}
</ul>
```
Another nested loop feature in Jinja templates is cycle, which does not exist in Django templates (as a variable at least, it does exist as a tag). The primary use of cycle is to define CSS classes so each iteration receives a different CSS class and upon rendering each iteration is displayed in a different color. The following snippet illustrates the use of the cycle variable.
```
{% for drink in drinks %}
<li class="{{ loop.cycle('odd','even') }}">{{ drink.name }}</li>
{% endfor %}
```
Note cycle can iterate sequentially over any number of strings or variables (e.g. `{{ loop.cycle('red' 'white' 'blue') }}`).
* {% for %} with recursive keyword.-
The {% for %} statement also supports recursion over nested dictionaries, lists, tuples or string variables. Instead of creating multiple nested {% for %} statements, you can use recursion to re-use the same layout over each of the nested structures. Listing 4-16 illustrates a sample of a recursive loop in Jinja.
Listing 4-16. Jinja {% for %} statement with recursive keyword
```
# Dictionary definition
coffees={
'espresso':
{'nothing else':'Espresso',
'water': 'Americano',
'steamed milk': {'more steamed milk than milk foam': 'Latte',
'chocolate syrup': {'Whipped cream': 'Mocha'}
},
'more milk foam than steamed milk': 'Capuccino'
}
}
# Template definition with for and recursive
{% for ingredient,result in coffees.iteritems() recursive %}
<li>{{ ingredient }}
{% if result is mapping %}
<ul>{{ loop(result.iteritems()) }}</ul>
{% else %}
YOU GET: {{ result }}
{% endif %}</li>
{% endfor %}
```
```
# Output
espresso
water YOU GET: Americano
steamed milk
more steamed milk than milk foam YOU GET: Latte
chocolate syrup
Whipped cream YOU GET: Mocha
more milk foam than steamed milk YOU GET: Capuccino
nothing else YOU GET: Espresso
```
The {% break %} and {% continue %} statements are available inside {% for %}. but {% break %} and {% continue %} **require enabling the built-in jinja2.ext.loopcontrols extension**
* range (Function)
For example, range(0,5) generates the range [0,1,2,3,4]. In addition, the range function also supports overriding the step count -- which defaults to 1 -- in the third position (e.g. range(0,11,2) generates [0,2,4,6,8,10]).
* cycler (Function)
The cycler function lets you cycle among a series of values. It works just like the loop.cycle variable available in {% for %} loops, except the cycler function can be used outside loops.
The cycler function uses its next() method to advance one item, the reset() method to cycle to the first item and the current attribute to return the current item. Listing 4-17 illustrates a cycler method definition with CSS classes, which is then used over multiple {% for %} loops to define a list where each item is assigned a different CSS class based on the cycle iteration.
Listing 4-17 Jinja cycler function
```
{% set row_class = cycler('white','lightgrey','grey') %}
<ul>
{% for item in items %}
<li class="{{ row_class.next() }}">{{ item }}</li>
{% endfor %}
{% for otheritem in moreitems %}
<li class="{{ row_class.next() }}">{{ otheritem }}</li>
{% endfor %}
# Output
<ul>
<li class="white">Item 1</li>
<li class="lightgrey">Item 2 </li>
<li class="grey">Item 3 </li>
<li class="white">Item 4</li>
<li class="lightgrey">Item 5</li>
<li class="grey">Other item 1</li>
<li class="white">Other item 2</li>
</ul>
```
* joiner (Function)
The joiner function lets you join a series of disparate sections and join them with a given separator, which defaults to a comma-space (", "). A characteristic of the joiner function is that it returns the separator string every time it's called, except the first time to give the correct appearance in case sections are dependent on a condition. Listing 4-18 illustrates a joiner method definition with a slash-space ("/ ") as its separator, which is then used to join a list of sections.
Listing 4-18 Jinja joiner function
```
{% set slash_joiner = joiner("/ ") %}
User: {% if username %} {{ slash_joiner() }}
{{username}}
{% endif %}
{% if alias %} {{ slash_joiner() }}
{{alias}}
{% endif %}
{% if nickname %} {{ slash_joiner() }}
{{nickname}}
{% endif %}
# Output
# If all variables are defined
User: username / alias / nickname
# If only nickname is defined
User: nickname
# If only username and alias is defined
User: username / alias
# Etc, the joiner function avoids any unnecessary preceding slash
# because it doesn't print anything the first time its called
```
## Python and filter operations
.. review the docs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment