How to repeat a "block" in a django template

49,154

Solution 1

I think that use of the context processor is in this case an overkill. You can easily do this:

#base.html
<html>
    <head>
        <title>{% block title %}My Cool Website{% endblock %}</title>
    </head>
    <body>
        {% block content %}{% endblock %}
    </body>
</html>

and then:

# blog.html
{% extends 'base.html' %}
{% block content %}
    <h1>{% block title %}My Blog{% endblock %}</h1>
    Lorem ipsum here...
{% endblock %}

and so on... Looks like DRY-compatible.

Solution 2

You probably don't actually want to use a block but rather to just use a variable:

# base.html
<html>
    <head>
        <title>{{ title|default:"My Cool Website" }}</title>
    </head>
    <body>
        <h1>{{ title|default:"My Cool Website" }}</h1>
    </body>
</html>

You then set the title through the context.

Solution 3

Here's a way I discovered when trying to do the same thing myself:

# base_helper.html
<html>
    <head>
        <title>{% block _title1 %}{% endblock %}</title>
    </head>
    <body>
        <h1>{% block _title2 %}{% endblock %}</h1>
    </body>
</html>


# base.html
{% extends "base_helper.html" %}

# Copy title into _title1 & _title2, using "My Cool Website" as a default.
{% block _title1 %}{% block _title2 %}{% block title %}My Cool Website{% endblock %}{% endblock %}{% endblock %}

Requires an extra file unfortunately, but doesn't require you to pass the title from the view.

Solution 4

you can use {% include subtemplate.html %} more than once. it's not the same as blocks, but does the trick.

Solution 5

There are some discussion here: http://code.djangoproject.com/ticket/4529 Obviously django core team reject this ticket because they think this is not a common used scenario, however I disagree.

repeat block is simple and clean implementation for this: https://github.com/SmileyChris/django-repeatblock

template macros is another one, however the author mentioned it's not carefully tested: http://www.djangosnippets.org/snippets/363/

I used repeatblock.

Share:
49,154
David Arcos
Author by

David Arcos

Director of Engineering at Bling, teacher at ESADE, and organizer at PyBCN. I'm a technology generalist, coming from a strong technical background as a Python developer specialized in security, scalability and distributed systems. For the past 15 years, I've worked at several startups, building cloud platforms in sectors as diverse as video streaming, computer vision, in-flight entertainment, machine learning, cyber-security, healthcare, and fintech. I'm also teaching Cloud Computing at ESADE, organizer at the Python Barcelona Association, and a speaker at a number of technical conferences and webinars.

Updated on December 18, 2020

Comments

  • David Arcos
    David Arcos over 3 years

    I want to use the same {% block %} twice in the same django template. I want this block to appear more than once in my base template:

    # base.html
    <html>
        <head>
            <title>{% block title %}My Cool Website{% endblock %}</title>
        </head>
        <body>
            <h1>{% block title %}My Cool Website{% endblock %}</h1>
        </body>
    </html>
    

    And then extend it:

    # blog.html
    {% extends 'base.html' %}
    {% block title %}My Blog{% endblock %}
    
    # pictures.html
    {% extends 'base.html' %}
    {% block title %}My Pictures{% endblock %}
    
    # cats.html
    {% extends 'base.html' %}
    {% block title %}My Cats{% endblock %}
    

    I will get an exception, as Django wants the block to appear only once:

    TemplateSyntaxError at /

    'block' tag with name 'title' appears more than once

    A quick and dirty solution would be duplicating the block title into title1 and title2:

    # blog.html
    {% extends 'base.html' %}
    {% block title1 %}My Blog{% endblock %}
    {% block title2 %}My Blog{% endblock %}
    

    But this is a violation of the DRY principle. It would be very difficult as I have a lot of inheriting templates, and also because I don't wanna go to hell ;-)

    Is there any trick or work-around to this problem? How can I repeat the same block in my template, without duplicating all the code?

  • Van Gale
    Van Gale about 15 years
    This has the same problem. The base template won't know which subtemplate to include.
  • thebiglife
    thebiglife over 14 years
    I might try this tomorrow - I've been wondering how to save a bit of repetition in the templates and this seems like a good approach. thanks.
  • Roman Starkov
    Roman Starkov over 14 years
    In the end I settled for the {% macro %} solution, which doesn't require a new file, and overall lets me express exactly what I want to express.
  • lprsd
    lprsd over 14 years
    Probably Dry. But you wouldn't want to set the title within the view; but in the templates.
  • Guillaume Esquevin
    Guillaume Esquevin over 13 years
    Titles should be set from within the templates, not be provided by the context, you need to had a way to define this "title" variable, otherwise this is not a good solution.
  • Robert Lacroix
    Robert Lacroix almost 13 years
    I think that's the most elegant solution of all. Thanks Kieran and Van Gale!
  • SystemParadox
    SystemParadox over 12 years
    This approach is excellent. I've split out my base.html into base.html and superbase.html, so this also works if you wanted to put a standard title markup (like an h1) in your shared templates. Pages can still override the content of the title block and it will update in both locations.
  • Tobu
    Tobu about 12 years
    That's what the django admin templates do (for {{title}}), but defining the title at a remove is inconvenient.
  • acjay
    acjay over 11 years
    That's pretty slick, but it seems like it might be even better to render all of the nodes in the Set tag, otherwise they get rendered over and over again by Get. I can think of reasons that might be a good idea (rendering the same stored block inside of different blocks on a page), but I just thought I'd point it out.
  • Jonathan
    Jonathan almost 10 years
    However Any variable set in the context will only be available in the same block of the template in which it was assigned. This behavior is intentional; it provides a scope for variables so that they don’t conflict with context in other blocks.
  • natevw
    natevw over 9 years
    The original django-repeatblock repository seems to have been deleted. The best fork of that seems to be github.com/phretor/django-repeatblock; I also found github.com/ydm/django-sameas, which doesn't require a 'wontfix' Django patch.
  • Dennis Golomazov
    Dennis Golomazov over 9 years
    This doesn't allow to use the text more than twice, does it?
  • dqd
    dqd about 9 years
    Denis Golomazov: No. In that case, it is better to use the macro plugin (see below).
  • François Constant
    François Constant about 9 years
    This is a question about Django.
  • Mikael Lindlöf
    Mikael Lindlöf about 8 years
    Can also be applied the other way around: defining the h1 content inside the block that defines the title. Or a block that defines a part of the title.
  • Wtower
    Wtower over 7 years
    Please note that include is slower than block. docs.djangoproject.com/en/1.10/topics/performance/…
  • TheKalpit
    TheKalpit about 6 years
    Neat! This approach also lets you define different content, if you need to, in each block.
  • benzkji
    benzkji almost 6 years
    simpel and efficient. unlike @dqd s answer, the blocks dont need to be nested, very useful for example for facebook og tags, that might have the same content as other head attributes. upvote!
  • Anupam
    Anupam almost 6 years
    Great answer. This seems even DRYer than @dqd's answer since you have dont have to repeat the <h1> tag in each template that inherits base. This could be the accepted answer.
  • caram
    caram over 4 years
    Excellent! I've used this in more complex scenarios where I wanted to repeat the footer row of a table a the top. And the <tr> row was rather complex.
  • Elendurwen
    Elendurwen over 2 years
    Still works in 2021!
  • Flimm
    Flimm over 2 years
    Which snippet is this answer referring to?