I have two models like this:
class ClassA(models.Model):
ida = models.AutoField(primary_key=True)
classb = models.ForeignKey(ClassB)
name = models.CharField(max_length=765)
class ClassB(models.Model):
idb = models.AutoField(primary_key=True)
name = models.CharField(max_length=765)
I want to show a list of all my ClassA objects grouped under a ClassB heading. This is the view I have:
def show_class_a_objects(request):
class_b_objects = ClassB.objects.all().order_by('name')
class_a_objects = ClassA.objects.all().order_by('name')
return render_to_response('show_objects.html', {
'class_a_objects': class_a_objects, 'class_a_objects': class_a_objects,
})
My show_objects.html file looks like this:
{% extends "base_show.html" %}
{% block content %}
</p>
<table>
<th align="left">Name</th>
{% for b in class_b_objects %}
<tr>
<td>{{b.name}}</td>
</tr>
{% for a in class_a_objects %}
{% ifequal a.classb b %}
<tr>
<td><a href="{{ a.get_absolute_url }}">{{a.name}}</a></td>
</tr>
{% endifequal %}
{% endfor %}
{% endfor %}
</table>
</br>
{% endblock %}
Is there a better way of doing this instead of using the two nested for loops?
You don’t need to query the ClassA objects like this to achieve the grouping you want. When you create a ForeignKey on your ClassA -> ClassB, your ClassB will contain a relation that will give you back all ClassA objects which have ClassB as a ForeignKey:
view
template
You still need a nested for loop, but you no longer have to loop over the entire range of every single other class and do comparisons to find the right ones.
If you want a bit more control, you should move this into your view again and prebuild the dict:
view
template
Update: Reducing number of queries
As per the comments, I wanted to address the issue of increasing the amount of database queries from your original 2, to the amount of
1 + num_of_classb_objects. This is because while the original ClassB query is 1, each of theb.classa_set.all()relation calls is another query to fetch the related ClassA instances.If you want to try and test an alternative, you can check out this blog post on efficient reverse lookups
Example (adapted from link to your model names):
Also, if you are running django >= 1.4, this functionality is supposedly official in the form of
prefetch_related.I have not tested this, but I wanted to present it as something for you to look into if
n+1queries are not acceptable to you.