Django's {% include with var="val" %} updates context - django

I just figured out, that if you include subtemplate using with, variables will be available in base template. Very easy to reproduce:
Test: {{ test }}
{% include "tpl.txt" with test="passed" %}
Test: {{ test }}
Output:
Test:
Test: passed
Is it a bug?
UPD. I must say that inside tpl.txt there is inclusion tag with take_context=True. Also this inclusion tag do this:
#register.inclusion_tag('my_tag.txt', takes_context=True)
def my_tag(context):
context.update({'new': 'key'})
return context
If you don't update context, or if you do context['new'] = 'key' it works as expected. If you do update - all the variables you pass to {% include %} using with become available later in template. Still it's kind of wierd, because variables become available in parent template, and not updated keys ("new") become available, but {% include %} variables. The problem is localized though.

Related

Extending base.html conditionally, in Django template

Based upon whether a custom-defined context variable {{ state }} is true or false, I want to extend a different flavor of base.html in a Django template.
What's the Django template code to make this happen?
I'm trying: {% extends state|yesno:"base1.html;base2.html" %} but unsure whether this is correct.
You are almost there - you just need to replace your semi-colon ; with a commma ,:
{% extends state|yesno:"base1.html,base2.html" %}

django context to built-in pages

I have a template that looks something like:
Main Template, home.html:
{% extends "framed.html" %}
<h2> stuff <h2>
framed.html looks something like
{% block header %}
<h1>{{ sitename }}</h1>
{% endblock %}
Normally when I call these views I give it a context with a context containing a key "sitename" assigned get_current_site().name, which works fine.
I also, however, would like to use framed.html at the top of a bunch of templates that are also called by django default views. For example:
return HttpResponseRedirect(reverse('django.contrib.auth.views.login'))
The top of that page never gets the {{sitename}} to show up, so I end up with some blank space at the top of my page. The same goes for flat pages, logouts, etc. Is there a way I can get the relevant context added to all of these "built-in" pages?
You can write your own template context processor that will add required variable in the parameters provided to each template.
More details at Writing your own context processors

update value of a variable inside a template - django

I have seen enough number of examples that allow me to declare a new variable inside a template and set its value. But what I want to do is to update the value of a particular variable inside the template.
For example I have a datetime field for an object and I want to add timezone according to the request.user from the template. So I will create a template filter like {% add_timezone object.created %} and what it will do is that it will add timezone to object.created and after that whenever I access {{object.created}} it will give me the updated value.
Can anybody tell me how this can be done. I know I need to update the context variable from the template filter. But don't know how.
You cannot modify a value in a template, but you can define 'scope' variables using the {% with %} tag:
{% with created=object.created|add_timezone %}
Date created with fixed timezone: {{ created }}
{% endwith %}
where add_timezone is a simple filter:
def add_timezone(value):
adjusted_tz = ...
return adjusted_tz
register.filter('add_timezone', add_timezone)

Conditional include tag in Django

I've ran into very strange behavior of Django template system. I have a template file, namely test.html, which recursively includes itself:
{% include "test.html" %}
Of course, such template has no chance to be rendered, since there is no finishing condition. OK, let's try the following:
{% if test_false %}{% include "test.html" %}{% endif %},
where test_false is a variable passed to template and equal to False.
One expects that it just will not include anything, but it does:
RuntimeError at /test/
maximum recursion depth exceeded while calling a Python object
I don't get it. Include tag can take arguments from current context, so I doubt it is executed before any other part of the page. Then why does it ignore condition tag?
Django has optimization that include templates that are given by constants at compilation.
Set name of template to variable and include it in that way:
{% include test_template %}
Django will not be able to use it's optimization and your code should work.
Like Thomasz says, Django can only make this optimization if the path is defined as a constant string in the including template - like so:
{% include "test.html" %}
But I would rather not have to put the template path in the context from Python code.
So here is a slightly more self contained way of achieving the same result - wrap the include in a with:
{% with "test.html" as path %}
{% include path %}
{% endwith %}

Django: cannot pass variable to included template?

I got a problem where I want to use template including in Django.
Here is the real example:
I got 3 files:
home.html (will get the context variable passed from Views)
base.html (the skeleton template file)
and the header.html (included by base.html).
If I put the code below directly in base.html without including header.html, the {{title}} variable passed from home is correctly called. But if I include the header.html in base.html, the {{title}} variable's value cannot be called.
<title>{% block title %}{% endblock %} | {{ SITE_INFO_TITLE }}</title>
Is there any solution to this problem? Thanks.
Could you just pass in a variable within the {% include %} tag? It's documented here: https://docs.djangoproject.com/en/1.5/ref/templates/builtins/#include
{% include "name_snippet.html" with person="Jane" greeting="Hello" %}
As far as I know blocks and variable are distinct in django.
If you want to pass title as a context variable you have to set it using a declaration in base.html such as :
{% include "header.html"%}
Which in turn contains :
{% block title %} {{title}} {%endblock%}
You can also set it in home like this.
{% block title %} Home page {%endblock%}
But I also try to set in the template context.
Without the title block.
def test_view(ctx):
xa = { "title":"Sommaire"}
return render_to_response("test.html",xa)
I think you can also see the with template tag I think it is possible to set a context variable using this tag.
You can use Inclusion Tags to render an additional template from within a Django template. You can additionally pass the 'child' template context from the 'parent' template.
It's a little involved for your use case but it solves your problem. I tend to use it when I'm looping a list to render each item with a custom template. I can then reuse that template elsewhere without duplicating the markup if I need to render another item of the same type.