I have recently started to learn Django, so I came across with some HTML templates, but those are pretty unfamiliar for me, they mostly consist of {% and {{
For example:
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
Vote again?
What are they? Implementations from other languages or HTML syntax? I'd be happy to get some docs, websites or examples too.
The {% _________ %} are template tags. They are used to interpolate a tag into the space. Examples include extend, include, and load to name but a few. They often extend, insert, or give some sort logical functionality in some way (if conditions or loops, etc).
The {{ ___________ }} syntax is for template variables. This is used to interpolate a variable declared either as one of the built-in options or your own which you have created from any number of methods (models, view context, etc).
The Django docs are pretty thorough with use cases of all these. Another website which shortlists these to make them readily understandable is https://www.djangotemplatetagsandfilters.com/
It doesn't mean anything in html itself, it means something in Django template language. For example:
{{ choice.choice_text }}
will substitute value of that variable during template rendering.
The other one {% and %} is used for template processing, for example to indicate to template processor that some task needs to be completed. Good example is:
{% if error %}
{{ error }}
{% endif %}
That means that the variable error will be displayed (rendered) only if it exists, or to be more precise if it has some value.
The ones you are referring are jinja codes. They are very essential to work with Django and also they easy to understand when you have general understanding about python and django. You can find the documentation about jinga in this URL Jinja2 Documentation
Related
I'm building an admin for Flask and SQLAlchemy, and I want to pass the HTML for the different inputs to my view using render_template. The templating framework seems to escape the HTML automatically, so all <"'> characters are converted to HTML entities. How can I disable that so that the HTML renders correctly?
To turn off autoescaping when rendering a value, use the |safe filter.
{{ something|safe }}
Only do this on data you trust, since rendering untrusted data without escaping is a cross-site scripting vulnerability.
MarkupSafe provides Jinja's autoescaping behavior. You can import Markup and use it to declare a value HTML safe from the code:
from markupsafe import Markup
value = Markup('<strong>The HTML String</strong>')
Pass that to the templates and you don't have to use the |safe filter on it.
From the Jinja docs section HTML Escaping:
When automatic escaping is enabled everything is escaped by default
except for values explicitly marked as safe. Those can either be
marked by the application or in the template by using the |safe
filter.
Example:
<div class="info">
{{data.email_content|safe}}
</div>
When you have a lot of variables that don't need escaping, you can use an autoescape override block:
{% autoescape false %}
{{ something }}
{{ something_else }}
<b>{{ something_important }}</b>
{% endautoescape %}
For handling line-breaks specifically, I tried a number of options before finally settling for this:
{% set list1 = data.split('\n') %}
{% for item in list1 %}
{{ item }}
{% if not loop.last %}
<br/>
{% endif %}
{% endfor %}
The nice thing about this approach is that it's compatible with the auto-escaping, leaving everything nice and safe. It can also be combined with filters, like urlize.
Of course it's similar to Helge's answer, but doesn't need a macro (relying instead on Jinja's built-in split function) and also doesn't add an unnecesssary <br/> after the last item.
Some people seem to turn autoescape off which carries security risks to manipulate the string display.
If you only want to insert some linebreaks into a string and convert the linebreaks into <br />, then you could take a jinja macro like:
{% macro linebreaks_for_string( the_string ) -%}
{% if the_string %}
{% for line in the_string.split('\n') %}
<br />
{{ line }}
{% endfor %}
{% else %}
{{ the_string }}
{% endif %}
{%- endmacro %}
and in your template just call this with
{{ linebreaks_for_string( my_string_in_a_variable ) }}
Use the safe filter in your template, and then sanitize the HTML with the bleach library in your view. Using bleach, you can whitelist the HTML tags that you need to use.
This is the safest, as far as I know. I tried both the safe filter and the Markup class, and both ways allowed me to execute unwanted JavaScript. Not very safe!
I followed instructions in simmilar thread like: How do you index on a jinja template?
but my html template is not working and whole django project is not responding due to this.
Error that I'm getting:
Error during template rendering.
Could not parse the remainder: '[loop.index0]' from 'songs_titles[loop.index0]'
My code looks like this:
{% if converted_files_urls %}
<p>Titles: {{ songs_titles }}</p>
{% for n in converted_files_urls %}
<a href="{{ n }}" download>Download: {{ songs_titles[loop.index0] }}</a>
<br/>
{% endfor %}
{% endif %}
and the {{ songs_titles }} renders as list, so at least till here it works ok.
What am I doing wrong?
Actually you are looking for Jinja, that will not work on django.
In django template tag you should use forloop.counter0 and list indexing looks like
{{songs_titles.1}}
Need to set count in variable and then use it, for setting variable you could use -
{% with index=forloop.counter0 %}
{{ songs_titles.index}}
{% endwith %}
Still If you have any doubts you can comment it.
I finally resolved this by creating a custom template tag like here:
https://djangosnippets.org/snippets/2740/
But to be honest it sucks that that's the simplest working solution for now :/
In jinja I can create macros and call it in my template like this:
{% macro create_list(some_list) %}
<ul>
{% for item in some_list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endmacro %}
HTML code....
{{ create_list(list1) }}
{{ create_list(list2) }}
{{ create_list(list3) }}
I read in django docs that django templates hasn't macro tag. I'm interested in the best way to do something like this in django templates.
As you already said macros don't exist in django's templating languages.
There are template tags to do more difficult things in templates, but that's not what you're looking for either, because django's templating system also doesn't allow parameters being passed to functions.
The best thing for your example would be to use the include tag:
https://docs.djangoproject.com/en/1.8/ref/templates/builtins/#include
Here's how I would use it:
templates/snippets/list.html
<ul>
{% for item in list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
templates/index.html
{% include 'snippets/list.html' with list=list1 %}
{% include 'snippets/list.html' with list=list2 %}
{% include 'snippets/list.html' with list=list3 %}
...
I found two packages to offer that:
https://github.com/twidi/django-templates-macros
https://github.com/nalourie/django-macros
they both look to work the same: install with pip, put in INSTALLED_APPS, {% load macros %} in the template, write and use them.
template/partials/example-partial.html
{%if partial_name == 'partial1'%}
<ul>
{% for item in list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{%endif%}
{%if partial_name == 'partial2'%}
<ul>
{% for item in list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{%endif%}
{%if partial_name == 'partial3'%}
<ul>
{% for item in list %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{%endif%}
templates/index.html
{% include 'partials/example-partial.html' with list=list1 partial_name="partial1"%}
{% include 'partials/example-partial.html' with list=list2 partial_name="partial2"%}
{% include 'partials/example-partial.html' with list=list3 partial_name="partial3"%}
... just start using jinja with Django.
it's very easy to turn it on
and you can use both template engines at the same time, of course for different files.
In the Django Template Language macros are not supported, but you can select the Jinja engine in order to use macros. Keep in mind that if you are building a plugable application, Django recommends using the DTL.
A Django project can be configured with one or several template
engines (or even zero if you don’t use templates). Django ships
built-in backends for its own template system, creatively called the
Django template language (DTL), and for the popular alternative
Jinja2.
The Django template language is Django’s own template system. Until
Django 1.8 it was the only built-in option available. It’s a good
template library even though it’s fairly opinionated and sports a few
idiosyncrasies. If you don’t have a pressing reason to choose another
backend, you should use the DTL, especially if you’re writing a
pluggable application and you intend to distribute templates. Django’s
contrib apps that include templates, like django.contrib.admin, use
the DTL.
Here is the link to the documentation for configuring other template engines: https://docs.djangoproject.com/en/dev/topics/templates/#configuration
I have a set of articles (using pelican for generating static sites) which includes a category called hotels. I'd like to sort these hotels. The problem is that only the hotels have an attribute called 'city' while the other articles do not and this obviously leads to the following error:
Caught exception "'pelican.contents.Article object' has no attribute 'city'".
Here is the code I am using:
{% for article in articles|sort(attribute='city') %}
{% if article.category == 'hotels' %}
<a href="hotels/{{ article.slug }}.html">
<p>{{ article.title }}</p>
</a>
{% endif %}
{% endfor %}
Is there a way to check to see if the attribute exists and provide some default value so that it does not cause an error?
You may be able to move your if statement into your for loop as a filter:
for article in articles if article.category == 'hotels' | sort(attribute='city')
If you want to show only entries that have a 'city' attribute, and have that list sorted by 'city', do:
for article in articles|selectattr("city")|sort(attribute="city")
If you want to iterate over only the hotels, see Sean Vieira's answer. If you want to iterate over all articles, but have the hotels sorted while the rest are in arbitrary order, you can do it by using macros:
{% macro my_macro(article) %}
...
{% endmacro %}
{% for a in articles if a.category == 'hotels' | sort(attribute='city') %}
{{ my_macro(a) }}
{% endfor %}
{% for a in articles if a.category != 'hotels' %}
{{ my_macro(a) }}
{% endfor %}
This will include everything you defined in my_macro first for each hotel, in the desired order, then for each article that is not a hotel.
I found this page when was looking for a similar solution.
Eventually, I solved it a bit differently and it might be helpful for someone else.
In one of my templates for Pelican I added statistics collected by 'post_stats' plugin about approximate time to read. It looked like
~{{ article.stats['read_mins']|default("0") }} min read
But if the plugin is not loaded then the 'article' object doesn't have the 'stats' attribute and rendering fails.
Jinja has the builtin test for testing if a variable is defined.
So, I came up with this solution
~{{ article.stats['read_mins'] if article.stats is defined else "0" }} min read
For me this works:
{{ game.description|safe }}
But this fails:
{{ game.description|safe|slice:"65" }}
Is there a way to apply two or more filters on a variable in Django templates?
Although it's quite past when the OP posted the question, but for other people that may need the info, this seems to work well for me:
You can rewrite
{{ game.description|safe|slice:"65" }}
as
{% with description=game.description|safe %}
{{description|slice:"65"}}
{% endwith %}
Is description an array or a string?
If it is a string, you might want to try truncatewords (or truncatewords_html if the description can contain HTML),
{{ game.description|safe|truncatewords:65 }}
Reference: Built-in filter reference, truncatewords.
(I'm new to Django so my apologies if slice works on strings.)
change
{{ game.description|safe|slice:"65" }}
to
{{ game.description|safe|slice:":65" }}
you are missing the colon
This may work:
{% filter force_escape|lower %}
This text will be HTML-escaped, and will appear in all lowercase.
{% endfilter %}
Reference: Built-in tag reference, filter.