简体   繁体   中英

Passing a variable to include in extends in Django templates

I have the following structure of templates:

main.html

<html>
<body>
  <p>
    This works: {% block title %}{% endblock %}
  </p>

  {% include 'heading.html' with title=title %} {# but this does not work since it is not a variable #}
</body>
</html>

heading.html

<p>
  {{ title }}
</p>

page.html

{% extends 'main.html' %}

{% block title %}test title{% endblock %}

How can I pass the title from page.html to heading.html ? Ideally, it should be defined as a block like now, but alternatives are also welcome. I'd like to contain the solution within the templates if possible.

Clarification:

This is a minimal example, but I have multiple pages like main.html that share a larger header that has title and some other variables that I'd like defined in the child template (not necessarily as variable as long as the text is passed).

I could put the title into the view code, but this solution would just decrease the separation of displayed data from the logic.

One possible solution is to split heading.html into two and add a {% block %} in-between, but this is an ugly workaround that is prone to bugs with unclosed tags.

I am searching for a better alternative.

main.html

...
{% include 'heading1.html' %} {# containing <p> #}
{% block title %}{% endblock %}
{% include 'heading2.html' %} {# containing </p> #}
...

Additionally, if white spaces are important, there has to be no new line between includes and the block.

instead of {% include %}, you might want to use custom template tags with returning html or extension like slippers

add your title to the rendering context and it will be visible in page, main and included heading.

You don't need heading.html . You can use the context variable title directly; as long as you pass it to your render function in your view, eg:

views.py

def my_view(request):
    context = {'title': 'Hello World!'}
    return render(request, 'page.html', context=context)

main.html

<html>
<body>
  <p>
    This is my title:
    {% block title %}{% endblock %}
  </p>
</body>
</html>

page.html

{% extends 'main.html' %}

{% block title %}
  <strong>{{title}}</strong>
{% endblock %}

Use a block around the include with variables, and then wrap {{ block.super }} in the with template tag.

main.html:

<html>
<body>
  <p>
    This works: {% block title %}{% endblock %}
  </p>

  {% block with_variables %}
    {% include 'heading.html' %}
  {% endblock %}
</body>
</html>

page.html:

{% extends 'main.html' %}

{% block title %}test title{% endblock %}

{% block with_variables %}
    {% with title="variable title" %}
        {{ block.super }}
    {% endwith %}
{% endblock %}

You may name it {% block heading %} , or nest the whole main.html in {% block content %} .

If you have administrative rights to your Django installation, an easy and elegant solution would be to switch your Django's template renderer to Jinja2 instead using django-jinja as a backend.

The main advantage of Jinja2 for the needs of this question is that it supports assignment of a block to a variable through block assignments . Since Jinja2 is inspired by the Django template language, your existing templates will need few modifications, if any.

With Jinja2 as a template renderer, you can set the title variable with a block of HTML content in the child template:

page.html

{% extends 'main.html' %}

{% set title %}test title{% endset %}

The title variable will then work in the shared template:

main.html

<html>
<body>
  <p>
    Main template works: {{ title }}
  </p>
{% include 'heading.html' %}
</body>
</html>

And it will also work in the included template:

heading.html

  <p>
    Included template also works: {{ title }}
  </p>

Demo: https://replit.com/@blhsing/AlarmedCleverDebugmonitor

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM