Multiple django 'with' statements inside 'if' statement - django

I have a Django multiple 'with' statements inside 'if/elif' statement.
The blocks of code inside if/elif are the same except for one variable 'slide1_line2'.
I am wondering if there is a way to re-write code to avoid repetition.
{% if country == 'England' or country == 'Wales'%}
{% with graphic='map.png' %}
{% with classes='color-1' %}
{% with slide1_line1='Your constituency is '|add:name %}
{% with slide1_line2='Heading1' %}
{% with slide1_line3='text' %}
{% with icon='keyboard_arrow_down' %}
{% include 'slide_map.html' %}
{% endwith %}{% endwith %}{% endwith %}{% endwith %}{% endwith %}{% endwith %}
{% elif country == 'Scotland' or country == 'Northern Ireland' %}
{% with graphic='map.png' %}
{% with classes='color-1' %}
{% with slide1_line1='Your constituency is '|add:name %}
{% with slide1_line2='Heading2' %}
{% with slide1_line3='text' %}
{% with icon='keyboard_arrow_down' %}
{% include 'slide_map.html' %}
{% endwith %}{% endwith %}{% endwith %}{% endwith %}{% endwith %}{% endwith %}
{% endif %}

You can factor out the common values outside the if statement:
{% with graphic='map.png' classes='color-1' slide1_line1='Your constituency is '|add:name slide1_line3='text' icon='keyboard_arrow_down' %}
{% if country == 'England' or country == 'Wales' %}
{% include 'slide_map.html' with slide1_line2='Heading1' %}
{% else %}
{% include 'slide_map.html' with slide1_line2='Heading2' %}
{% endif %}
{% endwith %}
Note that:
you can define multiple variables in the same {% with … %} template tag [Django-doc]; and
the {% include … %} template tag [Django-doc] can have a {% include … with … %} clause to pass certain extra parameters.

Related

how to do assignments for variable in django template tag

I want to do assignment in Django template tag for this code:
{% for ins in ob %}
{% if ins.heur = 'here' %}
a==1
some stuff ..
{% endif %}
{% endfor %}
{% if a!=1 %}
stuff
{% endif %}
You can use the {% with %} template tag.
Example:
{% with a=1 %}
{{ a }}
{% endwith %}

`with` template tag with logical comparison result as value

Is there a way to assign a logical value from a comparison to a variable in the current context?
I tried :
{% with hidden=forloop.counter > 4 %}
{% include "path/to/template.html" %}
{% endwith %}
And it didn't work because that causes a syntax error. But perhaps there is just a syntax I don't know?
So far I do something like this :
{% if forloop.counter > 4 %}
{% with hidden=True %}
{% include "path/to/template.html" %}
{% endwith %}
{% else %}
{% include "path/to/template.html" %}
{% endif %}
And it works, But it looks dirty to me.
The include template tag allows you to pass extra context
{% if forloop.counter > 4 %}
{% include "path/to/template.html" with hidden=True %}
{% else %}
{% include "path/to/template.html" %}
{% endif %}

How do I implement a recursive and extensible Twig template?

I'm implementing a simple website menu, but this time I'm using Twig as my template language. The depth of the menu tree is one or greater. Here's my Twig code so far (sanitized and simplified):
{# file menu1.html.twig #}
<ul>
{% import _self as renderer %}
{% for item in menu.items %}
{{ renderer.renderItem(item) }}
{% endfor %}
</ul>
{% macro renderItem(item) %}
{% block itemtag %}
<li>
{% endblock %}
{{ item.name }}
{% if item.hasItems() %}
<ul>
{% import _self as renderer %}
{% for subitem in item.items %}
{{ renderer.renderItem(subitem) }}
{% endfor %}
</ul>
{% endif %}
</li>
{% endmacro %}
Now I need to override the "itemtag" element in another template:
{# file menu2.html.twig #}
{% extends "menu1.html.twig" %}
{% block itemtag %}
<li data-foo="bar">
{% endblock %}
This will not work, as explained very well here: https://stackoverflow.com/a/26650103/220817
So how do I write a Twig template that can traverse and render a tree structure, and still allow extending templates to override certain elements in the rendered markup?
You need to use macro's if you want to do something recursive as macro's can self import themself. Here is an example of a recursive macro:
{% macro menu(m, class, currentLevel, maxLevel) %}
{%if not class is defined %}
{% set class = '' %}
{% endif %}
{%if not currentLevel is defined or currentLevel is null %}
{% set currentLevel = 1 %}
{% endif %}
{%if m is iterable%}
{% set links = m %}
{% else %}
{% set links = m.getLinks() %}
{% if m.showRoot() and m.hasRoot() %}
<li class="root{%if class != ''%} {{class}}{%endif%}">
<a href="{%if m.getRoot().getTreeLeft() > 1 %}{{ m.getRoot().getRoute() }}{% else %}#site_url#{% endif %}" {% if m.getRoot().PageId in selected_page_ids %} class="selected"{% endif %}>{{ m.getRoot().name }}</a>
</li>
{% endif %}
{% if maxLevel is null %}{% set maxLevel = m.getLevel() %}{% endif %}
{% endif %}
{% if not links is empty %}
{% for link in links %}
{% if link['selected'] is defined and link['selected'] %}
{% set is_selected = true %}
{% else %}
{% set is_selected = false %}
{% endif %}
{% set anchor_class = '' %}
{% if link.PageId in selected_page_ids or is_selected %}
{% set anchor_class='selected' %}
{% endif %}
{% if method_exists(link, 'getPageCssClass') and link.getPageCssClass() != null %}
{% set class= class~' '~link.getPageCssClass().getTitle() %}
{% endif %}
<li{%if (class|trim) != '' %} class="{{ (class|trim) }}"{% endif %}>
<a href="{{ link.getRoute }}"{%if (anchor_class|trim) != '' %} class="{{ (anchor_class|trim) }}" {% endif %} {% if link.PageId > 0 %}data-page-id="{{ link.PageId }}"{% endif %}>{{ link.name }}</a>
{% if link.hasPublicChildren and currentLevel < maxLevel %}
<ul>
{{ _self.menu(link.getPublicChildren, 'sec', (currentLevel+1), maxLevel) }}
</ul>
{% endif %}
</li>
{% endfor %}
{% endif %}
{% endmacro %}

Conditional variable assignment

I'm doing this in one of my templates:
{% if activite.travel %}
{% with activite.travel.personne as personne %}
{% include 'includes/person_detail.html' %}
{% endwith %}
{% endif %}
{% if activite.relation %}
{% with activite.relation.src as personne %}
{% include 'includes/person_detail.html' %}
{% endwith %}
{% endif %}
Note: I may have more fields to come in activite that's why I'm not doing "else" but two separate "if".
I'd like to do something like:
{% if activite.travel %}
{% set personne=activite.travel.personne %}
{% elsif activite.relation %}
{% set personne=activite.relation.src %}
{% endif %}
{% include 'includes/person_detail.html' %}
Is there a way to do this in the template?
Not exactly... but you can use with inside of include
{% if activite.travel %}
{% include 'includes/person_detail.html' with personne=activite.travel.personne %}
{% elif activite.relation %}
{% include 'includes/person_detail.html' with personne=activite.relation.src %}
{% endif %}

Optimizing a django template full of {% regroup %} tags

I have a Django template full of nested {% regroup %} tags, and I have the feeling that it is one of the reason why it is so slow. Moreover, it is very complex to maintain like this. Do you have any advise and design patterns to make it faster and more sustainable? I'm open to any suggestion, including moving the logic to models or creating template tags...
Here is a snippet of code, with only the structure, to give you a taste of what it looks like...
{% extends "base.tex" %}
{% block content %}
{% for courseoutline in courseoutline_list %}
...
{% regroup courseoutline.coursemembership_set_by_teaching_unit by teaching_unit as course_list %}
{% for course in course_list %}
{% regroup course.list|dictsort:"course.title" by course.title as course_sublist %}
{% for course in course_sublist %}
{% with course.list|semester:1 as cc %}
...
{% for c in cc %}
...
{% endfor %}
{% endwith %}
{% with course.list|semester:2 as cc %}
{% for c in cc %}
{% endfor %}
{% endwith %}
{% endfor %}
{% endfor %}
{% regroup courseoutline.coursemembership_set_by_semester by semester as semester_list %}
{% for semester in semester_list %}
{% regroup semester.list by teaching_unit as ue_list %}
{% for ue in ue_list %}
{% for course in ue.list|dictsort:"code" %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endblock %}
Thanks!