Is space matter in Jinja? - django

What David has written in CS50 2022 - Lecture 9 - Flask, layout.html is
{% block body %}{% endblock %}
What I typically do in Django, a similar Python web framework is
{% block body %}
{% endblock %}
Is space matter in Jinja? Is it a matter of style? Because I know HTML is also space insensitive.

I do not believe spaces are important. Just there are replicated in the rendered template.
In template components most included, many spaces in the component can create many spaces in the rendered html that you will send to web client. I use the {% spaceless %}{% endspaceless %} for removing them in django template language.
In Jinja, you can set trim_blocks and lstrip_blocks on the env.
app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True
You can also use - for removing spaces in conditional block:
{%- if ... -%} --> strips before and after
You can use + for be sure to preserve space in same way.

Related

How to indent Django templates properly

I work in SublimeText 3. When writing Django templates I have a mixture of html and functions.
I like to indent my code so that block, if and other such statements are indented. For example:
Manual formatting
{% extends "accounts/base.html" %}
{% block content %}
<h1>Password changed</h1>
<p>Your password was changed.</p>
{% endblock %}
However, when I run any autoformatter HTML-CSS-JS-Prettify it ignores these brackets and treats them as text:
After formatting
{% extends "accounts/base.html" %}
{% block content %}
<h1>Password changed</h1>
<p>Your password was changed.</p>
{% endblock %}
Although plugins like Djaneiro give great tag highlighting, I haven't been able to find a way to get SublimeText to treat these as tags.
Has anyone had any luck?
This is a late answer, but I would like to mention a Django template formatter that I've created myself: DjHTML. You can install it using pip install djhtml.
Let's say template.html contains the following:
{% extends "accounts/base.html" %}
{% block content %}
<h1>Password changed</h1>
<p>Your password was changed.</p>
<script>
$(function() {
console.log("Password changed!");
});
</script>
{% endblock %}
Then running djhtml template.html will give the following output:
{% extends "accounts/base.html" %}
{% block content %}
<h1>Password changed</h1>
<p>Your password was changed.</p>
<script>
$(function() {
console.log("Password changed!");
});
</script>
{% endblock %}
It's easiest to use DjHTML as a pre-commit hook, so that templates will be automatically indented when you run git commit. Instructions on how to configure pre-commit can be found in the README.
There isn't one for sublime text as far as I can tell. I have no source I can quote on this, but I have basically searched nothing came up.
This discussion is by any means old, but active. I found this really old ticket about formatting standards for Django and it has been updated 9 Months ago to basically say they are "in favour of standards" and the proposed formatting for templates would be:
<ul>
{% for x in y %}
<li>{{ x }}</li>
{% endfor %}
</ul>
They also made a place happen that holds information about formatting guidelines in Django.
You might find this discussion interesting as well. It's old too, but it highlights the confusion about formatting in Django and the DIY solutions people came up with to cope.

Django nested templates

In trying to keep with DRY, I'm setting up my Django project HTML files now. I have successfully extracted most repeated information to my base.html page. On most (but not all) of my pages, my content is displayed within a general 'panel' which is basically just a container set-up with styling, but it's got a few div-tags to it so it looks a bit ugly and I'm having to type out the exact same code out several times on each page.
My idea was to extract this to a 'panel.html' then call it whenever I need it, for example some pages might just have one 'panel' whereas my dashboard (it's an administrative site) will have maybe 15+. So it seemed a better idea and cleaner to not have to type out all this code each time I need to set up a 'panel'.
My ideal page would look something like..
{% extends 'base.html' %}
{% block content %}
{% extends 'panel.html' %}
{% block panel_content %}
Panel content...
{% endblock panel_content %}
{% extends 'panel.html' %}
{% block panel_content %}
Second panel content
{% endblock panel_content %}
{% endblock content %}
I know I can't use extends multiple times but I'm using it just as an example for what it is I'm trying to achieve.
I am going to potentially have hundreds of these identical 'panels' across my site but each containing different content and it would be so much cleaner if I could just have one stored somewhere in a HTML file and call it however many times I need.
Is there a way to do this?
You can use include
{% include "panel.html" %}
I should mention that too many include statements create a performance issue.

Parsing and using list item content via Twig

I am experimenting with using Grav to create my next website. One of the things I would be able to do is to build a unordered list using data provided in Grav frontmatter from the Grav page that uses the template. Here is how I am trying to do this
---
sectionone:
listitems: "['Benefit 1','Benefit 2','Benefit 3']"
---
and then in the template somehow do the following
{% block featurelist %}
<ul>
{% set items = {{page.header.sectionone.consumers.benefits|json_decode}} %}
{% for item in {{}} %}
<li>{{item}}</li>
{% endfor %}
</ul>
{% endblock %}
However, Twig does not like this and reports back an error along the lines of
Twig_Error_Syntax
A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "punctuation" of value "{".
with the offending line being my {% set items = ... } statement. I am clearly doing something wrong here but I am a Twig newbie so I fail to see what that might be.
{% block featurelist %}
<ul>
{% set items = page.header.sectionone.consumers.benefits|json_decode %}
{% for item in items %}
<li>{{item}}</li>
{% endfor %}
</ul>
{% endblock %}
I figured this out eventually. Grav documentation is by and large very good. However, the documentation on page headers/frontmatter appears to be somewhat incomplete. There is no full description of the entire syntax that is understood by the frontmatter processor. In order to define an array in front matter all you need to do is the following
---
sectionone:
benefits:
- 'Benefit 1'
- 'Benefit 2'
- ...
---
In essence the standard markdown syntax for an unordered list. Grav's twig processor appears to convert this to a PHP array - no parsing required!

Detecting a URL in a Django wizard_form.html template

I have three SurveyWizardViews all of which use the same standard wizard_form.html which is located at templates/formtools/wizard/wizard_form.html as per the documentation
I have added some basic logic to this template which is designed to detect which page of the form the user is on so that I can include a non standard page/step, this is an image with a JS slider bar underneath. This all works perfectly.
{% if wizard.steps.current == '6' %}
<img src="{% static "survey/images/pathtwo/" %}{{display_image}}"/>
<section>
<span class="tooltip"></span>
<div id="slider"></div>
<span class="volume"></span>
</section>
{% endif %}
However I now want to have a slightly different experience for the user depending on which View/URL they are coming from.
Question Is it possible to detect which URL the view is currently using to look at the page? e.g.
{% if URL.current == 'www.mywebsite.com/experiment/surveyone/' %}
do X
{% if URL.current == 'www.mywebsite.com/experiment/surveytwo/' %}
do y
I have done some searching but Im not even sure what I'm searching for to be honest. Any help would be much appreciated.
You can use the request context variable. Something like:
{% if 'experiment/surveyone' in request.path %}
do this
{% endif %}
I prefer using in instead of == to ignore trailing and leading slashes. If you want the whole thing try the build_absolute_uri method. Also check what options does request offer to you (https://docs.djangoproject.com/en/dev/ref/request-response/#httprequest-objects).
Finally, don't forget to add django.core.context_processors.request to your TEMPLATE_CONTEXT_PROCESSORS (I think it is added by default).

Can we append to a {% block %} rather than overwrite?

In my core.html I have a block labeled javascript. It would be great if I can append more lines to this block without overwriting everything in it.
{% block javascript %}
{{ block.super }}
... more content ...
{% endblock %}
See: Django documentation - Template inheritance
Using block.super works fine when extending a template but not as well when including one, ie:
{% extends "base.html" %} vs. {% include "partial.html" %}
Say you want to include a template in the middle of your page and you'd also like it to add some javascript in a block at the end of the page: calling block.super in the included template will crash.
Cf. Django issues #7324, #12008, #13399 and the related update to the documentation. Cf. include tag note:
The include tag should be considered as an implementation of “render this subtemplate and include the HTML”, not as “parse this subtemplate and include its contents as if it were part of the parent”. This means that there is no shared state between included templates – each include is a completely independent rendering process.
Blocks are evaluated before they are included. This means that a template that includes blocks from another will contain blocks that have already been evaluated and rendered - not blocks that can be overridden by, for example, an extending template.
In that case I'd recommend using django-sekizai, wich allow you to do things like:
{% load sekizai_tags %}
⎧ <p>Some content</p>
<p>Some content</p> | {% addtoblock "js" %}
| <script type="text/javascript">
{% include "partial.html" %} -> ⎨ alert("Hello django-sekizai");
| </script>
<p>Some more content</p> ⎩ {% endaddtoblock %}
{% render_block "js" %}
From django-sekizai README:
The main reason I started this project was the lack of a good media (css/js) framework in django and the django-cms. Yes there is the Media class used in forms in django, but really that doesn't work that well. Usually the frontend guys want to decide on css and javascript files to be included and they don't want to have to edit Python files to change that neither did I want them to change my Python files. Therefor there was a need to allow you to edit contents of templates which are before or after the point where you are now. Also I wanted duplicates to be removed. As a result I wrote django-sekizai, which does exactly that. It's similar to blocks, just instead of inheriting them, you extend them.