我有两个与一对多相关的模型:
class Person(models.Model):
name = models.CharField(max_length=255);
surname = models.CharField(max_length=255);
age = models.IntegerField();
class Dog(models.Model):
name = models.CharField(max_length=255);
owner = models.ForeignKey('Person');
我想输出一份人员名单,并在每个人的下方列出他所拥有的狗。我就是这样做的:
在视图中:
persons = Person.objects.all()[0:100];
模板中的:
{% for p in persons %}
{{ p.name }} has dogs:<br />
{% for d in persons.dog_set.all %}
- {{ d.name }}<br />
{% endfor %}
{% endfor %}
但如果我这样做,Django将执行101个SQL查询,效率非常低。
我尝试制作一个自定义管理器,它将获取所有人,然后所有的狗并将它们链接在python中,但后来我不能使用paginator(我的另一个问题:Django: Paginator + raw SQL query)它看起来非常难看。
这样做有更优雅的方法吗?
更新
基于@Daniel Roseman博客录入的解决方案
all_objects = Person.objects.select_related().all();
paginator = Paginator(all_objects, 100);
try:
page = int(request.GET.get('page', '1'))
except ValueError:
page = 1
try:
current_page = paginator.page(page)
except (EmptyPage, InvalidPage):
current_page = paginator.page(paginator.num_pages)
person_list = dict([(obj.id, obj) for obj in current_page.object_list])
id_list = [obj.id for obj in current_page.object_list]
objects = Dog.objects.filter(owner__id__in=id_list)
relation_dict = {}
for obj in objects:
relation_dict.setdefault(obj.owner_id, []).append(obj)
for id, related_items in relation_dict.items():
person_list[id].dogs = related_items
答案 0 :(得分:1)
使用较新版本的Django(> = 1.7或甚至更旧的版本),您只需更换
persons = Person.objects.all()[0:100]
与
persons = Person.objects.prefetch_related('dog_set').all()[0:100]
就是这样,如果您使用的是Django&gt; = 1.7
,则无需继续使用旧的解决方法 prefetch_related
上的官方文档在这里:
https://docs.djangoproject.com/en/2.0/ref/models/querysets/#prefetch-related