I want to reduce the number of template filter calls in my_filter_function(). Because It's used inside two for-loops inside a template. Please see below for my code setup.
class ModelA(models.model):
models.ForeignKey(OtherModel1)
class ModelB(models.model):
models.ForeignKey(OtherModel2)
class ModelC(models.Model):
a = models.ForeignKey(ModelA)
b = models.ForeignKey(ModelB)
def my_views(request):
return render(request, 'my_template.html', {
'a_list': ModelA.objects.all(),
'b_list': ModelB.objects.all(),
})
and in my template, I have
{% for a in a_list %}
{% for b in b_list %}
{% with b|my_filter_function:a as my_val %}
Val: {{my_val}}
{% endwith %}
{% endfor %}
{% endfor %}
the above template will will call the my_filter_function filter function, I need to find another way to reduce the number of my_filter_function function calls, because the filter function is accessing the DBs several thousand times per template now.
@register.filter
def my_filter_function:(b, a):
z = ModelC.objects.filter(a=a, b=b)
if z.count() > 0:
return "OK"
else:
return "Not OK"
答案 0 :(得分:2)
Here's a faster alternative.
Fetch all the ids of A
and B
in C
at once:
z = ModelC.objects.values_list('a_id', 'b_id')
a_related, b_related = zip(*z) # split into a and b ids
Pass these to your context:
def my_views(request):
return render(request, 'my_template.html', {
'a_list': ModelA.objects.all(),
'b_list': ModelB.objects.all(),
'a_related': a_related,
'b_related': b_related,
})
And then use if...in
in your template. The custom template filter can now be discarded:
{% for a in a_list %}
{% for b in b_list %}
{% if a.id in a_related and b.id in b_related %}
"OK"
{% else %}
"Not ok"
{% endif %}
{% endfor %}
{% endfor %}
That replaces all the multiple queries in your filter with just one.