Django:获取对象列表的相关记录列表

时间:2010-03-28 11:19:59

标签: django foreign-keys

我有两个与一对多相关的模型:

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

1 个答案:

答案 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