我有两个这样的模型:
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)
我想显示分组在 ClassB
标题下的所有 ClassA
对象的列表。这是我的看法:
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,
})
我的 show_objects.html
文件如下所示:
{% 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 %}
除了使用两个嵌套的 for 循环之外,是否有更好的方法来执行此操作?
最佳答案
def show_class_a_objects(request):
class_b_objects = ClassB.objects.all().order_by('name')
class_a_objects = ClassA.objects.all().order_by('name')
您不需要像这样查询 ClassA 对象来实现您想要的分组。当您在 ClassA -> ClassB 上创建外键时,您的 ClassB 将包含一个关系,该关系将返回所有将 ClassB 作为外键的 ClassA 对象:
查看
def show_class_a_objects(request):
class_b_objects = ClassB.objects.all().order_by('name')
return render_to_response('show_objects.html', {
'class_b_objects': class_b_objects,
})
模板
{% for b in class_b_objects %}
<tr>
<td>{{b.name}}</td>
</tr>
{% for a in b.classa_set.all %}
<tr>
<td><a href="{{ a.get_absolute_url }}">{{a.name}}</a></td>
</tr>
{% endfor %}
{% endfor %}
您仍然需要一个嵌套的 for 循环,但您不再需要循环遍历每个其他类的整个范围并进行比较以找到正确的类。
如果你想要更多的控制,你应该再次将其移到你的 View 中并预构建字典:
查看
def show_class_a_objects(request):
class_b = ClassB.objects.all().order_by('name')
class_b_objects = [(b, b.classa_set.all().order_by('name')) for b in class_b]
return render_to_response('show_objects.html', {
'class_b_objects': class_b_objects
})
模板
{% for b, a_list in class_b_objects %}
<tr>
<td>{{b.name}}</td>
</tr>
{% for a in a_list %}
<tr>
<td><a href="{{ a.get_absolute_url }}">{{a.name}}</a></td>
</tr>
{% endfor %}
{% endfor %}
更新:减少查询数量
根据评论,我想解决将数据库查询量从原来的 2 个增加到 1 + num_of_classb_objects
的问题。这是因为,虽然原始 ClassB 查询为 1,但每个 b.classa_set.all()
关系调用都是另一个查询,用于获取相关的 ClassA 实例。
如果您想尝试测试替代方案,可以查看 efficient reverse lookups 上的这篇博客文章
示例(改编自您的型号名称的链接):
qs = ClassB.objects.all()
obj_dict = dict([(obj.id, obj) for obj in qs])
objects = ClassA.objects.filter(classb__in=qs)
relation_dict = {}
for obj in objects:
relation_dict.setdefault(obj.classb_id, []).append(obj)
for id, related_items in relation_dict.items():
obj_dict[id]._related_items = related_items
此外,如果您运行的是 django >= 1.4,此功能据说是官方形式的 prefetch_related
.
我还没有对此进行测试,但我想将其呈现给您,以便您了解是否无法接受 n+1
查询。
关于python - 有没有更简单的方法来按类别显示我的对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11237058/