Is there any reason why you can't compare a template filter to a string in Django template syntax? - django

I'm trying to do this, and failing. Is there any reason why it wouldn't work in Django template syntax? I'm using the latest version of Django.
{% ifequal entry.created_at|timesince "0 minutes" %}

It doesn't work because it's not supposed to work. What you're asking for is not part of the template language.
You can't apply a filter in the middle of tag like {% ifequal. When a template tag uses a variable, it doesn't expect an expression, it expects a variable, nothing more.
That kind of logic -- extracting time since, comparing, etc. -- is what you're supposed to do in your view function.
Your view function then puts a "zerominutes" item in the context for the template to use. Templates just can't do much processing.
They're designed to do the minimum required to render HTML. Everything else needs to be in your view function.

{% ifequal %} tag doesn't support filter expressions as arguments. It treats whole entry.created_at|timesince as identifier of the variable.
Quik workaround: introduce intermediate variable with expresion result using {% with %} like this:
{% with entry.created_at|timesince as delta %}
{% ifequal delta "0 minutes" %}
....
{% endifequal %}
{% endwith %}

See ticket #5756 and links in its comments for more information. A patch for Django in ticket #7295 implements this functionality. A broader refactoring of the template system based on #7295 is proposed in ticket #7806, and it would fix this issue among others.
I don't think making such comparisons to work would be against the design philosophy of Django templates.

I think you can, though I don't see any uses of it my code base. Maybe entry.created_at|timesince isn't producing the value you expect. Try putting
X{{entry.created_at|timesince}}X
into your template and seeing what value it produces. The X's are so you can see leading or trailing space, in case that is the problem.

I finally gave up on using the Django template language for anything other than the simplest pages. Check out Jinja2 for an almost-syntax-compatible alternative. And yes, you can choose which to use on a page-by-page basis.

Related

Django-templates: Concatenate string variables with strings in with block

So I'm looking to do something like this to keep things DRY:
{% with share_text=author.name + "released" + book.title + "via:myapp" %}
do stuff with {{share_text}}
{% endwith %}
However, I'm getting Django template errors like "could not parse remainder" and "with received invalid operator +".
Django template language is NOT python (ever if it sometimes looks a bit similar), so don't expect python code to work here. Use template filters / tags. In your case the builtin add templatefilter should work:
{% with share_text=author.name|add:"released"|add:book.title|add:"via:myapp" %}
but please carefully read the limitations and gotchas mentioned in the doc. Else you can write your own custom filter or templatetag, that's really easy.

django template tag on multiple line

I am creating a custom django template tag by using such a code :
#register.simple_tag(takes_context=True)
def render_listing(context, *args, **kwargs):
... my code ...
This works well, but in my template, it seems that all parameters must be on a single line, for example :
this works:
{% render_listing param1=val1 param2=val2 ... paramN=valN %}
but on multiple lines, it does not work :
{% render_listing param1=val1
param2=val2
...
paramN=valN %}
I tried multiple escape sequences but I did not succeeded,
Is there a way to specify a template tag on multiple lines ?
No, the Django template language does not support multiple line tags. See ticket 8652, which was closed as WONTFIX, or this thread from the django-developers mailing list.
Sometimes, if there is a repeated prefix, you can make it more readable by using the with tag. For example if you have,
{% render_listing param1=long.common.prefix.val1 param2=long.common.prefix.val2 param2=long.common.prefix.val3 %}
you could rewrite as
{% with prefix=long.common.prefix %}
{% render_listing param1=prefix.val1 param2=prefix.val2 param2=prefix.val3 %}
{% endwith %}
Often (but not always), a really long tag is an indication that you're putting too much logic in the template. See if you can move some of it into the view, model method, template tag or template filter.
It's pretty straightforward to enable, though hackish:
import re
from django.template import base
base.tag_re = re.compile(base.tag_re.pattern, re.DOTALL)
"Using" it is simple; one place I find it especially useful is {% include %} tags:
{% include 'my/sweet/modal-template.template' with
message="Hey, do you really want to frob the widget?"
yes="Heck yes I do!"
no="No frickin' way!"
icon="error"
%}
I haven't tested this in more recent versions of Django but I imagine it could be adapted; that worked at least back around 1.8. I should point out that in theory some tags that do custom parsing of their arguments could break; in practice I haven't had any trouble in the last ~10 years of Django programming.

Tag or inherit the same code in Django template with minor changes

I have a bunch of code that I will need to use repeatedly on a page, and on multiple pages. For example, here is a shorter version of the code:
<a href="#"
data-toggle="popover"
title="{% for terms in s_terms %}{% if terms.slug == 'neuron' %}{{terms.title}}{% endif %}{% endfor %}"
data-content="{% for terms in s_terms %}{% if terms.slug == 'neuron' %}{{terms.para_one}}{% endif %}{% endfor %}">
Toggle popover
</a>
There is a lot more code in the block. Now, for obvious reasons I do not want to keep repeating such large chunks of code. I am a fan of the DRY approach.
However, I can't figure out how to render this same piece of code repeatedly. The only thing that would change is the word = "neuron" in there. I thought of using template tags, but that didn't work.
I tried saving the code as a separate file, and inherit it within my template, but then I can't change the keyword ('neuron'). I also tried creating a separate dynamic page, and include that in my Django template, but looks like the include tag only works for templates, and not for dynamic pages.
Can anyone help, please? Thank you, in advance.
You could use Django template built-in template tag include.
From the documentation:
Loads a template and renders it with the current context. This is a
way of “including” other templates within a template.
So, you can just extract your snippet in a separate template and then use it with:
{% include "snippet_template.html" %}
Additionally, you can pass a variable to the include template using the with keyword - you would use this to pass your word parameter:
{% include "snippet_template.html" with word="neuron" %}
As #bonidjukic wrote the include statement is what you search.
But include statement inside for-loop could reach one weakness of Django template Engine (vs Jinja). You include just variables, so it will be fast.
In the case of needing tags (like trans), Django will load tags at each include. Where Jinja will have global "tags".
So just be careful, with how you DRY you templates.

{% with %} templatetag to avoid query execution multiple times?

If I use for example {{ some_model.objects.all }} in several places in one template, will the query be executed each time? And if so, should I always use {% with some_model.objects.all as some_name %} to avoid that? I saw this in several apps, so I'm wondering if I understand it correctly.
Yes, it does repeat the query. You should populate the context in your view instead of calling these functions within the template.
Using {% with %} indeed does solve the problem though for future calls, but I still vote for the view.
PS:
I highly suggest downloading django-debug-toolbar
https://github.com/dcramer/django-debug-toolbar
You can test these ideas in a second : )

Is using the "escape" tag really mandatory as a good security pattern in Django?

In the security chapter of The Django Book, it says that I must always use the template tag {% escape %} in order to protect my site from cross-site scripting.
Is it really necessary to put the escape tag on every single template string? Is there a way to specify this at application level?
That version of the Django book was written well before 1.0 came out, and is significantly out of date. All template content has been autoescaped for quite some time now.
In django is been done automatically. To turn it off you have to use the autoescape tag. I'm not sure since when, but at least since 1.1 version.
{% autoescape off %}
safe stuff
{% endautoscape %}