Separating ManyToManyFields in a template - django

Following my question at link text I'd like to separate the features in the template using categories such as Interior, Exterior, Mechanical etc.
I'm trying out the code below, but apparently it's not giving me what I want.
{% for feature in vehicle.features.all %}
{% ifequal vehicle.features.type.type "Interior" %}
<li>{{ feature }}</li>
{% endifequal %}
{% endfor %}
How do I go about this?

You want:
{% for feature in vehicle.features.all %}
{% ifequal feature.type.type "Interior" %}
<li>{{ feature }}</li>
{% endifequal %}
{% endfor %}
vehicle.features is a ManyToManyRelatedManager which can be used to access Feature objects, but does not actually carry Feature's relationships.
EDIT: In response to the comment below about doing this on the view, you could easily do:
interior_features = vehicle.features.filter(type__type='Interior')
and pass interior_features to the context of the template directly. This would actually make more sense as a method on the model:
def get_interior_features(self):
return self.features.filter(type__type='Interior')
The result of this could be filtered further, of course, as needed.
options = vehicle.get_interior_features().filter(is_standard=False)
or something.

Use Django's regroup tag: http://docs.djangoproject.com/en/dev/ref/templates/builtins/#regroup
Would probably end up looking something like:
{% regroup vehicle.features.all by type as vehicle_features %}
{% for feature in vehicle_features %}
{% ifequal feature "Interior" %}
<li>{{feature}}</li>
{% endifequal %}
{% endfor %}

Related

tags are not getting displayed in template, Django

context['d_tags'] = Blog.objects.filter(is_published=True).values('tags__name').order_by('tags__name').distinct()
print(context['d_tags'])
this prints the out put as below
<QuerySet [{'tags__name': 'ev'}, {'tags__name': 'yoga'}]>
how can I show it on templates, tried the following way
{% for tag in d_tags.all %}
<li>{{ tag }}</li>
{% endfor %}
gives an out put in template as
{'tags__name': 'ev'}
{'tags__name': 'yoga'}
but if I do this way
{% for tag in d_tags.all %}
<li>{{ tag.name }}</li>
{% endfor %}
doesn't gives any thing in display, how I can get just the values in template
You said #root's solution doesnt work, but it should... Are you sure you tried {{tag.tags__name}} and not something else?
Another solution would be opening double for loops...
{% for tag in d_tags %}
{% for tag_name in tag %}
<li>{{ tag_name }}</li>
{% endfor %}
{% endfor %}
But hey, thats really the same thing as saying {{tag.tags__name}}

Ifchanged if not null

I have the following logic in my template:
{% for task in tasks %}
{% ifchanged task.shared_task_id %}
<tr>{{ task }}</tr>
{% endifchanged %}
{% endfor %}
However, I want to ignore the ifchanged tag if the shared_task_id is None. Something like:
{% ifchanged task.shared_task_id or if task.shared_task_id == None %}
<tr>{{ task }}</tr>
{% endifchanged %}
Is there a way to do this?
Try this (edited with Hieu's fix):
{% ifchanged task.shared_task_id %}
<tr>{{ task }}</tr>
{% else %}
{% if not task.shared_task_id %}
<tr>{{ task }}</tr>
{% endif %}
{% endifchanged %}
Not really adhering to the DRY principle, but way less hackish that what you're using now. Django's template language is not really meant for advanced logic, so I don't think there are any better solutions.
If you need to print a lot of stuff instead of just {{ task }}, I think the best way to not repeat yourself abundantly and ease the pain of updating your code is to use a separate template and use {%include <other_template> %}.
I am doing this by a sort of hackish way in the model now:
{% ifchanged task.shared_task_id_or_random %}
# models.py
def shared_task_id_or_random(self):
return self.shared_task_id or str(random.random())
Any better ideas on how to fix this?
Since you can't have and and or logic in {% ifchange %}, you can always use 2 if blocks to achieve what you want:
{% for task in tasks %}
{% ifchanged task.shared_task_id %}
<tr>{{ task }}</tr>
{% else %}
{% if task.shared_task_id == None %}
<tr>{{ task }}</tr>
{% endif %}
{% endifchanged %}
{% endfor %}

Django template: check for empty query set

Is there a way to check for an empty query set in the Django template? In the example below, I only want the NOTES header to be displayed if there are notes.
If I put an {% empty %} inside the "for" then it does display whatever is inside the empty tag, so it knows it's empty.
I'm hoping for something that does not involve running the query twice.
{% if notes - want something here that works %}
NOTES:
{% for note in notes %}
{{note.text}}
{% endfor %}
{% endif %}
Clarification: the above example "if notes" does not work - it still displays the header even with an empty query set.
Here's a simplified version of the view
sql = "select * from app_notes, app_trips where"
notes = trip_notes.objects.raw(sql,(user_id,))
return render_to_response(template, {"notes":notes},context_instance=RequestContext(request))
Edit: the view select selects from multiple tables.
Have a look at the {% empty %} tag.
Example from the documentation
<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% empty %}
<li>Sorry, no athletes in this list.</li>
{% endfor %}
</ul>
Link: https://docs.djangoproject.com/en/1.8/ref/templates/builtins/#for-empty
If you are interested in a table, or some kind of heading if there are results, add the forloop.first:
{% for athlete in athlete_list %}
{% if forloop.first %}
Athlete Name:
{% endif %}
{{ athlete.name }}
{% empty %}
Sorry, no athletes in this list.
{% endfor %}
Try {% if notes.all %}. It works for me.
In your view check whether notes is empty or not. If it is then you pass None instead:
{"notes": None}
In your template you use {% if notes %} as normal.
It's unfortunate that you're stuck using a raw query set - they're missing a lot of useful behavior.
You could convert the raw query set into a list in the view:
notes_as_list = list(notes)
return render_to_response(template, {"notes":notes_as_list},context_instance=RequestContext(request))
Then check it as a boolean in the template:
{% if notes %}
Header
{% for note in notes %}
{{ note.text }}
{% endfor %}
{% endif %}
You could also make it happen without conversions using forloop.first:
{% for note in notes %}
{% if forloop.first %}
Header
{% endif %}
{{ note.text }}
{% endfor %}
What about:
{% if notes != None %}
{% if notes %}
NOTES:
{% for note in notes %}
{{ note.text }}
{% endfor %}
{% endif %}
{% else %}
NO NOTES AT ALL
{% endif %}
Your original solution
{% if notes %}
Header
{% for note in notes %}
{{ note.text }}
{% endfor %}
{% endif %}
Works now with Django 1.7 and thanks to QuerySet caching, it does not cost and extra query.
Often the right way to do this is to use the {% with ... %} tag. This caches the query so it runs only once and also gives you more flexibility with your markup than using {% empty %}.
{% with notes as my_notes %}
{% if my_notes %}
<ul>
{% for note in my_notes %}
<li>{{ note }}</li>
{% endfor %}
</ul>
{% else %}
<p>Sorry, no notes available</p>
{% endif %}
{% endwith %}
With this particular example I'm not sure how useful it is but if you're querying Many-to-Many field, for instance, it's likely what you want to do.
Use {% empty %} in django templates
{% if list_data %}
{% for data in list_data %}
{{ data.field_1 }}
{% endfor %}
{% else %}
<p>No data found!</p>
{% endif %}
We can write above code with {% empty %}.
{% for data in list_data %}
{{ data.field_1 }}
{% empty %}
<p>No data found!</p>
{% endfor %}

Interpolate Django template include variable

I'm doing something like
{% for part in parts %}
{% include "inc.html" with o=part prefix="part{{ forloop.counter0 }}_" %}
{% endfor %}
where inc.html could be something of such kind:
<p id="{{ prefix }}para">{{ o.text }}</p>
I just discovered the prefix variable isn't interpolated and "part{{ forloop.counter0 }}_" is passed literally.
Any relatively elegant work-around?
I think the best solution would be to register an inclusion_tag, that would handle the part and forloop.counter operations:
#register.inclusion_tag("inc.html")
def inc_tag(part, loop_counter):
prefix = 'part%s_' % (loop_counter,)
context = {
'part': part,
'prefix': prefix,
}
return context
And you would call it like that
{% for part in parts %}
{% inc_tag part=part loop_counter=forloop.counter0 %}
{% endfor %}
Your way is also doable like so, but I wouldn't recommend that
{% for part in parts %}
{% with "part"|add:forloop.counter0|add:"_" as prefx %}
{% include "inc.html" with o=part prefix=prefix %}
{% endwith %}
{% endfor %}

Problem with django templates

Is there any solution to do something like this:
{% for c in categories %}
{% for s in c.subcategory_set %}
<li>{{ s.name }}</li>
{% endfor %}
{% endfor %}
???
Reverse relations on a FK have a manager. As such, you need to use the all() method if you want to access all related objects.
{% for s in c.subcategory_set.all %}