Problem with django templates - django

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 %}

Related

How do I check if a many-to-many relationship exists in a Django template?

In this code example, "teaches_for" is the name of a many-to-many field that relates a Performer model to a School model. I want to include this particular block only if at least one relationship between a Performer and a Teacher model exists.
Here's my non-working code:
{% if performer.teaches_for.exists %}
<h3>{{performer.first_name}} teaches at these schools...</h3>
<ul>
{% for school in performer.teaches_for.all %}
<li>{{ school.name }}</li>
{% endfor %}
</ul>
{% endif %}
The line that's wrong is {% if performer.teaches_for.exists %}. What can I replace it with which will be True if at least one relationship exists, but False otherwise?
The relevant field in my Performer model looks like this:
teaches_for = models.ManyToManyField(
School,
verbose_name="Teaches at this school",
blank=True,
related_name="teachers",
)
Try {% if performer.teaches_for.all.exists %}.
In django 3.2.4 Hagyn's answer needs correction: {% if performer.teaches_for.all.exists() %}
And now it works as needed
The {% for school in performer.teaches_for.all %} loop will execute zero times if there are no schools. So put the header into the loop with a test on forloop.first.
{% for school in performer.teaches_for.all %}
{% if forloop.first %}
<h3>{{performer.first_name}} teaches at these schools...</h3><ul>
{% endif %}
<li>{{ school.name }}</li>
{% if forloop.last}</ul> {%endif%}
{% endfor %}
If I've cut-and-pasted from the question right.

Iterate through Django queryset within template

I have created a custom filter that returns a queryset of objects.
in: templatetags
#register.filter(name = 'create_html_for_deleting_notes')
def create_html_for_deleting_notes(task_pk):
corresponding_notes = Note.objects.filter(its_task = Task.objects.filter(pk = task_pk))
return(corresponding_notes)
in template:
{% for corresponding_task in corresponding_tasks %}
<h5>{{ corresponding_task | create_html_for_deleting_notes }}<h5/>
{% endfor %}
This works in printing out my queryset. I would like to iterate through that queryset, something like:
in template:
{% for corresponding_task in corresponding_tasks %}
{% for note in corresponding_task | create_html_for_deleting_notes %}
{{ note }}
{% endfor %}
{% endfor %}
But this gives me the error 'for statements should use the format "for x in y"'
Thank you for the help!
You need to remove the spaces around the filter | character.
However, I don't think you need the filter at all. You didn't post your model, but it seems like you have a foreignkey relationship between Task and Note, so you should just use the reverse accessor:
{% for corresponding_task in corresponding_tasks %}
{% for note in corresponding_task.note_set.all %}
{{ note }}
{% endfor %}
{% 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 %}

Django: How to write an if statement

I want to get the list of songs under the list of artists.
My artist class just contains the artists first and last name.
My song class contains a foreign key of an artist along with the song title.
I am able to list the artists but when I try to list the songs of the artist I get and error in my {% endif %} that ends my if statement {% if song %}.
{% extends "base.html" %}
{% block heading %}Music Catalog{% endblock %}
{% block content %}
{% if user.username %}
<p>Welcome {{ user.username }}!</p>
{% if artist %}
<u1>
{% for singer in artist %}
<li>{{ singer.firstname }} {{ singer.lastname }}</li>
{% if song %}
<u1>
{% for songs in song %}
{% if (songs.artist.firstname == singer.firstname
and songs.artist.lastname == singer.lastname) %}
<li>{{ songs.title }}</li>
{% endif %}
{% endfor %}
</u1>
{% endif %}
{% endfor %}
</u1>
{% else %}
<p>No artists were found in the music catalog.</p>
{% endif %}
{% else %}
<p>You need to login to see your music catalog.</p>
{% endif %}
{% endblock %}
enter code here
I don't think so, in the template language if statement you can use round bracket it won't parse. Try by removing it...
{% if songs.artist.firstname == singer.firstname and songs.artist.lastname==singer.lastname%}
It seems that your view should be handling more of this logic. Like Raunak Agarwal mentioned if you are passing your song or songs in to the template then each one is going to be the same.
It's very strange as well to be doing a
{% for songs in song %}
That just doesn't read right.
I would visit the view a little closer. I had written some more below. After looking over your code though taking a look at the view as well as the model would shed some light on things and allow for a much better help/answer to be given.
As you said My song class contains a foreign key of an artist along with the song title. - why don't you just use the regroup feature?
{% regroup song by artist as artist_list %}
<ul>
{% for artist in artist_list %}
<li>{{ artist.grouper }}
<ul>
{% for songs in artist.list %}
<li>{{ songs.title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Yes, your if song line is incorrect. It's quite clear from the template that you don't even have a song attribute at that point. Where is it supposed to be coming from? Presumably it's a related set on singer, but you haven't said so in the template.
You probably want something like this:
{% for singer in artist %}
<li>{{ singer.firstname }} {{ singer.lastname }}
{% with songs as singer.song_set.all %}
{% if songs %}
<ul>
{% for song in songs %}
<li>{{ song.title }}</li>
{% endfor %}
</uL>
{% endif %}
{% endwith %}
</li>
{% endfor %}
I've also removed that comparison of artist firstname and lastname, that didn't seem to make sense: you're already iterating through the set of songs from that artist, so no comparison is needed.

Separating ManyToManyFields in a template

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 %}