Reputation: 1570
I have two models, A and B, and B is ForienKey relationship to A.
I want to check each object in queryset and if it has certain fields then I want to display it in template.
Below is my template example:
{% for a in a_qs %}
<tr>
<th>{{ a.b_set.first.a_field }}</th>
<th>{{ a.b_set.first.another_field }}</th>
{% endfor %}
They work fine, but I want to apply something like get
method in queryset. Below is what I want to achieve:
{% for a in a_qs %}
<tr>
<th>{{ a.b_set.get(a_field_in_B='hello').a_field }}</th>
<th>{{ a.b_set.get(a_field_in_B='hello').another_field }}</th>
{% endfor %}
I understand that something above is not possible and I want to give some change to my views
or models
, but I don't know where to start.
Below is something like my views.py snippet:
a_qs = A.objects.all()
a_obj = a.b_set.get(a_field='something') # a is not defined yet. I want every a in a_qs to be checked
Thanks for your advice in advance.
Upvotes: 1
Views: 73
Reputation: 476557
Django templates are deliberately restricted to not allow method calls with parameters, as well as subscripts, etc. The reason is that business logic does not belong in the templates, but in the views.
You can make use of a Prefetch
object [Django-doc] to load objects per item. This will normally be faster as well, since all the related objects are loaded in bulk:
from django.db.models import Prefetch
a_qs = A.objects.prefetch_related(Prefetch(
'b_set',
B.objects.filter(a_field='something'),
'b_filtered'
))
If you pass this to the template, you can render this with:
{% for a in a_qs %}
<tr>
<th>{{ a.b_filtered.0.a_field }}</th>
<th>{{ a.b_filtered.0.another_field }}</th>
</tr>
{% endfor %}
or more elegant:
{% for a in a_qs %}
<tr>
{% with b_first=a.b_filtered.0 %}
<th>{{ b_first.a_field }}</th>
<th>{{ b_first.another_field }}</th>
{% endwith %}
</tr>
{% endfor %}
Upvotes: 1