How to pass selected, named arguments to Jinja2's include context? - templates

Using Django templating engine I can include another partial template while setting a custom context using named arguments, like this:
{% include "list.html" with articles=articles_list1 only %}
{% include "list.html" with articles=articles_list2 only %}
As you may be supposing, articles_list1 and articles_list2 are two different lists, but I can reuse the very same list.html template which will be using the articles variable.
I'm trying to achieve the same thing using Jinja2, but I can't see what's the recommended way, as the with keyword is not supported.

Jinja2 has an extension that enables the with keyword - it won't give you the same syntax as Django, and it may not work the way you anticipate but you could do this:
{% with articles=articles_list1 %}
{% include "list.html" %}
{% endwith %}
{% with articles=articles_list2 %}
{% include "list.html" %}
{% endwith %}
However, if list.html is basically just functioning as a way to create a list then you might want to change it to a macro instead - this will give you much more flexibility.
{% macro build_list(articles) %}
<ul>
{% for art in articles %}
<li>{{art}}</li>
{% endfor %}
</ul>
{% endmacro %}
{# And you call it thusly #}
{{ build_list(articles_list1) }}
{{ build_list(articles_list2) }}
To use this macro from another template, import it:
{% from "build_list_macro_def.html" import build_list %}

This way you can pass multiple variables to Jinja2 Include statement - (by splitting variables by comma inside With statement):
{% with var_1=123, var_2="value 2", var_3=500 %}
{% include "your_template.html" %}
{% endwith %}

For readers in 2017+, Jinja as of 2.9 includes the with statement by default. No extension necessary.
http://jinja.pocoo.org/docs/2.9/templates/#with-statement
In older versions of Jinja (before 2.9) it was required to enable this feature with an extension. It’s now enabled by default.

Updated 2021+
Included templates have access to the variables of the active context by default. For more details about context behavior of imports and includes, see Import Context Behavior.
From Jinja 2.2 onwards, you can mark an include with ignore missing; in which case Jinja will ignore the statement if the template to be included does not exist. When combined with with or without context, it must be placed before the context visibility statement. Here are some valid examples:
{% include "sidebar.html" ignore missing %}
{% include "sidebar.html" ignore missing with context %}
{% include "sidebar.html" ignore missing without context %}

Another option, without plugins, is to use macros and include them from another file:
file macro.j2
{% macro my_macro(param) %}
{{ param }}
{% endmacro %}
file main.j2
{% from 'macro.j2' import my_macro %}
{{ my_macro(param) }}

Related

Django Cycle Includes Template Tags

I want to cycle the include tags in a django template, but I am unable to nest cycle inside of includes. The cycle should be like
include cycle left_align.html right_align.html
I am trying to avoid creating a custom template just to keep it simple. I wanted to see if anyone had any suggestions of how to do this:
{% for s in sections %}
<section class="{% cycle 'lighter-section' 'cover cover-bg-section' %}">
{% if s.media.values %}
{% include 'web_builder/apple-pie/sections/left_align.html' %}
{% else %}
{% include 'web_builder/apple-pie/sections/center_align.html' %}
{% endif %}
</section>
{% endfor %}
Unfortunately there is no way to assign result of cycle templatetag to a variable with with block but you can use as keyword to dump its result to the variable and use it wherever you wish e.g. {% cycle 'left_align.html' 'right_align.html' as include_file %}. However this has a side effect.
This instruction itself produces cycle result although it is also registered in the variable. As a work-around you can place it for instance in a data- attr of some HTML element so that it isn't displayed and use the variable later in full template path concatenation inside include tag.
Full example:
{% for i in "xxxxxxxxxxxxxxxxx" %}
<section data-include-file="{% cycle 'left_align.html' 'right_align.html' as include_file %}">
{% include 'web_builder/apple-pie/sections/'|add:include_file %}
</section>
{% endfor %}
However since it looks ugly and complicated I would also consider writing custom inclusion tag for that.

How to access {% url "name" %} inside 'include' tag

I can't figure out how to get value of {% url "name" %} inside another {% %} tag. In my case its include
{% include "file" with next={% url "name" %} %}
This doesn't work. Do you know what to do? I would surround the {% include.. by {% with but it would cause the same problem.
Quick answer for django templates:
{% url "name" as my_url_context_var %}
{% include "file" with next=my_url_context_var %}
Lengthier explanation:
You cannot nest {% … %} or {{ … }}. The moment you open {{ … }}, you can only use context variables inside, optionally combined with template filters. Inside a {% … %}, you can only use whatever the tag you are using recognizes, but in general, that will be just a few arguments, some of which are static words (such as the as in the url above, or the with in the include), and often you can also access template variables and filters just like inside {{ … }}.
I'm not that familiar with jinja, but it seems that its include doesn't support the same kind of variable passing as django's include does, so here's an idea of what it might look like with jinja:
{% set next=url('name') %}
{% include "file" %}

How to pass HTML to an included template

Using Djangos template language I would like to pass HTML generated through the template language into an included template like in the following simplified example:
field.html
<input name="input_name" />
<div>{{ input_desc_html }}</div>
form.html
{% with input_name="test" input_desc_html=... %}
... should read {% for this in that %} {{ this }} {% endfor %}
{% include 'field.html' %}
{% endwith %}
Obvioulsy there is something missing at ... and I do not know how to advance from here. Is this approach even possible and if yes, how?
If not, what else would you suggest? I thought about using blocks and extending field.html, but it seems to me that this needs every field in its own file - or can I have local templates?

How to include templates dynamically in Django using "include" tag

I have 10 html files with the names 1.html, 2.html ..etc
What I want is according to a variable, a certain file should be included in the template.
e.g.
{% if foo.paid %}
{% include "foo/customization/{{ foo.id }}.html" %}
{% endif %}
Is this possible ? Cause the foo.id is not being translated before the includes tag works. As a result its giving a error. How can this issue be handled in a different way ?
Should I create a custom template tag for this ?
You can do it with add filter and with statement .
{% if foo.paid %}
{% with template_name=foo.id|stringformat:"s"|add:".html" %}
{% include "foo/customization/"|add:template_name %}
{% endwith %}
{% endif %}
First you build a template_name, which consist of foo.id in string format concatenated with .html. Then you pass it to include tag, concatenated with path to template directory.

Django pass object to include

I cannot do the following in Django:
{% include "admin/includes/pager.html" with title_pager="{{myobject.title}}" %}
or
{% include "admin/includes/pager.html" with title_pager="{{myobject}}" %}
What is the workaround?
You do not need to surround arguments in {{ }} brackets in template tags.
If it's a variable, not a string, then do not use "" quotes.
The following should work:
{% include "admin/includes/pager.html" with title_pager=myobject.title %}
{% include "admin/includes/pager.html" with title_pager=myobject %}
See the Django docs for the include tag for more information.