I am reading the source code of the Django application blog at git://github.com/nathanborror/django-basic-apps.git.
How do you read the following Django code?
{% tags_for_object object as tag_list %}
My attempt: Make the variable object of the type tags_for_object and rename the variable to tag_list.
The object apparently is based on the file blog/templates/inlines/default.html:
{% if object %}
{{ object }}
{% else %}
{% for object in object_list %}
{{ object }}
{% endfor %}
{% endif %}
What is the befefit of putting the logic to two-step procedure: run single object, else loop through a list of objects?
It looks like tags_for_object is the template tag from the django-tagging application.
From the django-tagging documentation:
tags_for_object:
Retrieves a list of Tag objects
associated with an object and stores
them in a context variable.
Usage:
{% tags_for_object [object] as [varname] %}
Example:
{% tags_for_object foo_object as tag_list %}
You can then loop through the tag_list variable in the template to display the tags.
{% tags_for_object foo_object as tag_list %}
<ul>
{% for tag in tag_list %}
<li>{{ tag }}</li>
{% endfor %}
</ul>
For the second part of your question, you understand the code correctly. If the variable object exists in the context (and doesn't evaluate to False), it is displayed. If it does not exist in the context (or if it evaluates to False), then the code loops through the objects in object_list, and displays them.
As for why you would want to do this, you would have to look at the code that uses inlines/default.html to work out what the designer had in mind.
Related
I am trying to simplify my code by creating a custom template tag for a 'for loop' that use frequently on my Django web application. I thought it would be a simple straight process, but something isn't working right... I can use some assistance in catching my error.
Here is my code.
views.py
class ArticleView(DetailView):
model = Articles
def get_context_data(self, **kwargs):
context = super(ArticleView, self).get_context_data(**kwargs)
context['s_terms'] = scientific_terms.objects.all()
return context
template tag
#register.filter(name='term')
def term(value):
{% for term in s_terms %}
{{ term.short_description }}
{% endfor %}
template.html
{% Neurons|term %}
Thank you for your assistance, in advance.
You are mixing Python code with the Django Template Language. The template tags are plain Python code, as they are defined inside a Python module. A working example would be:
#register.filter(name='term')
def term(terms):
output = ''
for term in terms:
output = '{0} {1}'.format(output, term.short_description)
return output
Then you could use it like this:
{{ s_terms|term }}
Maybe what you want is simply to create a reusable Django template.
For example, create a new template named terms.html:
templates/terms.html
{% for term in terms %}
<p>{{ term.short_description }}</p>
{% endfor %}
Then, in another template, you could include this partial template:
templates/index.html (name is just an example)
{% extends 'base.html' %}
{% block content %}
<h1>My application</h1>
{% include 'terms.html' with terms=s_terms %}
{% endblock %}
OK, so again there is likely a "simple" solution to this, but I am a beginner and nothing seems simple to me.
I have a view and a template that shows the attributes of an instance of a Car class that I have modeled. This Car class has a ManyToMany relationship with my custom User class. The template that show the attributes of a given instance of Car has many variables. The view for each Car works fine. Here is what I can't get to work:
I have a user profile page for each instance of User. From that page, I want to show the attributes of each Car that a particular User has "favorited." I am unable to figure out how to do this.
I have tried the {% include %} tag to include a snippet of the Car template and then use a for statement to iterate through the favorite set of the User. In theory, this would populate the User page with each Car that they have "favorited" and show its attributes. However, I do not know how to pass the {% include %} tag the proper context so the attributes are populated correctly for each instance of Car. Is this possible?
Is there a simpler way to do it that I am just overlooking?
Any help is appreciated. Thanks!
Use the {% include ... with ... %} syntax:
{% for car in user.favorite_cars.all %}
{% include "car.html" with name=car.name year=car.year %}
{% endfor %}
Another alternative is the {% with %} tag:
{% for car in user.favorite_cars.all %}
{% with name=car.name year=car.year %}
{% with color=car.color %}
{% include "car.html" %}
{% endwith %}
{% endwith %}
{% endfor %}
UPDATE: If data for the template can't be obtained from the Car model then you have to use the custom inclusion tag:
from django import template
register = template.Library()
#register.inclusion_tag('car.html')
def show_car(car):
history = get_history_for_car(car)
return {'name': car.name, 'history': history}
And the in the template:
{% load my_car_tags %}
{% for car in user.favorite_cars.all %}
{% show_car car %}
{% endfor %}
I'm building a website using Flask with its jinja2 templating engine and I'm dynamically building the menu (as described here):
{%
set navigation_bar = [
('/', 'index', 'Home'),
('/aboutus/', 'aboutus', 'About Us'),
('/faq/', 'faq', 'FAQ')
]
%}
{% set active_page = active_page|default('index') -%}
<ul>
{% for href, id, title in navigation_bar %}
<li{% if id == active_page %} class="active"{% endif %}>
{{ title|e }}
</li>
{% endfor %}
</ul>
Now if a user is logged in I want to show some additional things. So at runtime I want to add items to the navigation_bar variable. I tried something like this:
{% if g.user.is_authenticated() %}
{% navigation_bar.append(('/someotherpage', 'someotherpage', 'SomeOtherPage')) -%}
{% endif %}
But unfortunately this results in the following error: TemplateSyntaxError: Encountered unknown tag 'navigation_bar'. Jinja was looking for the following tags: 'endblock'. The innermost block that needs to be closed is 'block'.
So: does anybody know how I can add additional items to a jinja2 variable at runtime? All tips are welcome!
[bonus question]
I was also wondering, what does the - do at the end of {% set active_page = active_page|default('index') -%}?
The error occurs because Jinja can't identify block. Each Jinja block should start from block name. do block from do extension meets your needs. To use it you should add
do extension to jinja extensions. You can do this like so:
app.jinja_env.add_extension('jinja2.ext.do')
And then you can use do extension. Your example should looks like this:
{% if g.user.is_authenticated() %}
{% do navigation_bar.append(('/someotherpage', 'someotherpage', 'SomeOtherPage')) %}
{% endif %}
Here's another simple example.
You will find answer to your bonus question here. In short - removes whitespaces from start or end of block (this depends on where it is located).
To complete the answer of Slava Bacherikov, if you don't have the Jinja "do extension", you can use the tag set:
{% if g.user.is_authenticated() %}
{# use a dummy variable name, we juste need the side-effect of method call #}
{% set _z = navigation_bar.append(('/someotherpage', 'someotherpage', 'SomeOtherPage')) %}
{% endif %}
I have a dictionary called number_devices I'm passing to a template, the dictionary keys are the ids of a list of objects I'm also passing to the template (called implementations). I'm iterating over the list of objects and then trying to use the object.id to get a value out of the dict like so:
{% for implementation in implementations %}
{{ number_devices.implementation.id }}
{% endfor %}
Unfortunately number_devices.implementation is evaluated first, then the result.id is evaluated obviously returning and displaying nothing. I can't use parentheses like:
{{ number_devices.(implementation.id) }}
because I get a parse error. How do I get around this annoyance in Django templates?
Thanks for any help!
A workaround could be using the keys from number_devices and check in the for loop if it is equal to the key provided by number_devices.
{% for key in number_devices.keys %}
{% for implementation in implementations %}
{% ifequal key implementation.id %} you got it {% endifequal %}
{% endfor %}
{% endfor %}
Seems a bit ugly, but should work.
I have created a templatetag that loads a yaml document into a python list. In my template I have {% get_content_set %}, this dumps the raw list data. What I want to be able to do is something like
{% for items in get_content_list %}
<h2>{{items.title}}</h2>
{% endfor %}`
If the list is in a python variable X, then add it to the template context context['X'] = X and then you can do
{% for items in X %}
{{ items.title }}
{% endfor %}
A template tag is designed to render output, so won't provide an iterable list for you to use. But you don't need that as the normal context + for loop are fine.
Since writing complex templatetags is not an easy task (well documented though) i would take {% with %} tag source and adapt it for my needs, so it looks like
{% get_content_list as content %
{% for items in content %}
<h2>{{items.title}}</h2>
{% endfor %}`