Reputation: 12064
I have an car object in django view as follows:
'damages': [
{
"location": "Voorbumper",
"type": "Kras(10 cm, leger)",
"severity": "Light damage",
'comment': "This is some comment.",
"images": [
'http://pathtophoto.jpg',
'http://pathtophoto.jpg'
]
},
{
"location": "Vleugel rechts voor",
"type": "Deuk (Licht)",
"severity": "",
'comment': "",
"images": [
'http://pathtophoto.jpg',
'http://pathtophoto.jpg',
'http://pathtophoto.jpg'
]
},
{
"location": "Deur links voor",
"type": "Kras (5 cm, leger)",
"severity": "",
'comment': "",
"images": [
'http://pathtophoto.jpg'
]
},
{
"location": "Waterlijst",
"type": "Beschadigd",
"severity": "",
'comment': "",
"images": []
},
{
"location": "Antenne",
"type": "Ontbreekt",
"severity": "",
'comment': "",
"images": [
'http://pathtophoto.jpg'
]
},
{
"location": "Antenne",
"type": "Ontbreekt",
"severity": "",
'comment': "",
"images": []
}
]
I want to loop through that object and show the images of the damages. But I want first to show the damages with images, and the the damages without images with appropriate title.
In a django template I try to d it as follows:
{% for damage in car.damages %}
{% if damage.images|length > 0 %}
<div class="width-100 pad text-left primary-bg">{% trans "Shades met foto's" %}</div>
<div class="width-100 mar-top clear-float">
<div class="width-30 bord-my-way pad-half damage-info">
<div class="mar-btm-half"><b>{{ damage.location }}</b></div>
<div class="mar-btm-half">{{ damage.type }}</div>
<div class="mar-btm-half">{{ damage.severity }}</div>
<div class="mar-btm-half">{{ damage.comment }}</div>
</div>
<div class="width-70 pad-lft damage-photos">
{% for image in damage.images|slice:"3" %}
<div class="width-33 pad-rgh">
<img src="{{ image }}" class="width-100"/>
</div>
{% endfor %}
</div>
<div class="clear-float"></div>
{% if forloop.counter == 7 or forloop.counter == 14 or forloop.counter == 21 %}
<p style="page-break-before: always"></p> {% endif %}
</div>
{% endif %}
{% endfor %}
{% for damage in car.damages %}
{% if damage.images|length == 0 %}
<div class="width-100 pad text-left primary-bg mar-top">{% trans "Shades zonder foto's" %}</div>
<div class="green-bg">{{ damage.location }}</div>
{% endif %}
{% endfor %}
Thus, I first loop through damages where damage.images|length > 0
and then in the second for I check if there is no images with damage.images|length == 0
. But the title is shown for every for loop
iteration.
I could place the title's for the for loop
. Something like:
<div> Damages with photos </div>
{% for damage in car.damages %}
{% if damage.images|length > 0 %}
// Show it
{% endif %}
{% endfor %
And
<div> Damages without photos </div>
{% for damage in car.damages %}
{% if damage.images|length == 0 %}
// Show it
{% endif %}
{% endfor %
But sometimes I have only damages with images or only damages without images and then I see the title although I do not have any damages to show.
Is there any way to do something only once inside the if statement
, something like:
{% for damage in car.damages %}
{% if damage.images|length > 0 %}
<div>Damages with the photos</div> // Show it only once when it comes here
// Show the damages with photos
{% endif %}
{% endfor %}
{% for damage in car.damages %}
{% if damage.images|length == 0 %}
<div>Damages without the photos</div> // Show it only once when it comes here
// Show the damages without photos
{% endif %}
{% endfor %}
Any idea how to solve it?
Upvotes: 0
Views: 541
Reputation: 12086
What I would do in your position is
Either pass two separate QuerySet
s in the template, the first would include damages with images and the other damages without images.
Leave the QuerySet
as is and create two custom template filters that would do the same job as the step #1 above.
Case 1:
# views.py
def my_view(request):
damages_w_img = Damage.objects.filter(images__isnull=False)
damages_wo_img = Damage.objects.filter(images__isnull=True)
return render(request, 'template.html', locals())
<!-- template.html -->
{% if damages_w_img.exists %}
<h1>This list of damages contains images</h1>
{% for damage in damages_w_img %}
do stuff here, each damage has an image
{% endfor %}
{% endif %}
{% if damages_wo_img.exists %}
<h1>This list of damages does not contain images</h1>
{% for damage in damages_wo_img %}
do stuff here, each damage does not has an image
{% endfor %}
{% endif %}
Case 2:
# custom_template_filter.py
from django import template
register = template.Library()
@register.filter
def with_images(damages):
return damages.objects.filter(images__isnull=False)
@register.filter
def without_images(damages):
return damages.objects.filter(images__isnull=True)
<!-- template.html -->
{% with damage_w_img=car.damages|with_images damage_wo_img=car.damages|without_images %}
{% if damages_w_img.exists %}
<h1>This list of damages contains images</h1>
{% for damage in damages_w_img %}
do stuff here, each damage has an image
{% endfor %}
{% endif %}
{% if damages_wo_img.exists %}
<h1>This list of damages does not contain images</h1>
{% for damage in damages_wo_img %}
do stuff here, each damage does not has an image
{% endfor %}
{% endif %}
{% endwith %}
Upvotes: 0
Reputation: 681
I'm not overly familiar with Django and Python anymore, but I guess you could do a preliminary check to see if there are damages with or without images in there.
damages_with_images = [d for d in damages if d.images.length > 0]
damages_without_images = [d for d in damages if d.images.length == 0]
And then just loop over these two separate arrays, and only print the heading if they are not empty...
{% if damages_with_images|length > 0 %}
put heading1
{% endif %}
# ... loop ...
{% if damages_without_images|length > 0 %}
put heading2
{% endif %}
# ... loop ...
Of course this has worse performance because of multiple loops.
Upvotes: 1