Django: with tag outside blocks
Asked Answered
G

2

7

It seems like the 'with' tag is not working if it is declared outside of a block as this:

{% extends 'base.html' %}
{% with my_var=1 %}

{% block test1 %}
{{my_var}}
{% endblock %}

{% block test2 %}
{{my_var}}
{% endblock %}

{% endwith %}

The template above simply displays nothing since my_var is NOT passed inside those blocks. How can I overcome this?

Grisham answered 15/7, 2013 at 18:50 Comment(4)
I dont think block the reason. Can you just verifying by seeing if {% block test1 %}{% with my_var1=1 %}{{my_var1}}{% endwith %}{% endblock %} works ?Decelerate
@Decelerate Yes, I'm sure about this, just tested. I use Django 1.3 if it can be the reason.Grisham
I'm having the same issue with Django 1.6.1. Were you able to solve this problem?Dipteran
Django 1.10. I have it as well. Moving {% with ... %} inside the blocks make it work.Goldiegoldilocks
P
1

I came to Django from using Tornado with Jinja2 and I was being driven insane by the inability to set variables that (a) could be defined in the template (not view) and (b) would be available in the base template that this derives from. Looking at a little four-line piece of code from django-libs, I was able to rig up something like this that worked well. Here is an example of a title string that should appear in various blocks.

settings.py -- add to TEMPLATES (Django 1.10+)

TEMPLATES = {
   ...
   builtins = ['mysite...wherever...templatetags',]
}

mysite.whereever.templatetags.py

from django import template
register = template.Library()

@register.simple_tag(takes_context=True)
def setvar(context, key, value):
    context.dicts[0][key] = value
    return ''

base.html

{% block settings %}
    {% comment %}
          Put this at the TOP of the template before 
          any blocks that use variables.
    {% endcomment %}
{% endblock settings %}

<html>
<head><title>{{title}}</title></head>
<body><h1>My Site: {{title}}</h1>
{% block body %}
{% endblock body %}
</body></html>

menu.html -- a template that does not set 'title' in views:

{% extends "base.html" %}
{% block settings %}
    {{ block.super }} {% comment %}optional{% endcomment %}
    {% setvar 'title' 'Menu' %}
{% endblock %}
{% block body %}
     <ul><li>Fish</li><li>Steak</li></ul>
{% endblock %}

Now the title will appear in two places in the HTML even though it is defined in the derived template but appears in the top template.

Phrygia answered 7/1, 2018 at 22:28 Comment(3)
My God, man, you're fantastic! I was looking exactly for this solution. I have improved on it a bit, to make it more flexible.Kimbrough
for your reference: https://mcmap.net/q/1561050/-django-with-tag-outside-blocksKimbrough
Thanks @BarneySzabolcs -- I ended up switching to Jinja2 as a processor for Django because I had other situations I couldn't fix, but glad that this helped.Phrygia
K
1

Based on @MichaelScottAsatoCuthbert 's solution,

on top of templates/base.html:

{% block settings %}{% endblock %}
<!doctype html>
...

usage in page_template.html:

{% extends base.html %}
{% block settings %}
  {% setcontext title %}
    {% trans "I'm a translated title" %}
  {% endsetcontext %}
{% endblock %}

templatetags/setcontext.py:

from django import template
    
register = template.Library()
    
@register.tag(name="setcontext")
def do_setcontext(parser, token):
    nodelist = parser.parse(("endsetcontext",))
    params = token.split_contents()
    if len(params) != 2:
        raise template.TemplateSyntaxError(
            "'setcontext' tag requires exactly one argument")
    key = params[1]
    parser.delete_first_token()
    return SetContextNode(nodelist, key)
    
    
class SetContextNode(template.Node):
    def __init__(self, nodelist, key):
        self.nodelist = nodelist
        self.key = key

    def render(self, context):
        context.dicts[0][self.key] = self.nodelist.render(context).strip()
        return ''
Kimbrough answered 13/9, 2023 at 11:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.