【问题标题】:Django - reverse lookupsDjango - 反向查找
【发布时间】:2011-10-01 11:34:56
【问题描述】:

例如,我有这些模型:

class Person(models.Model):
    name = models.CharField(max_length=20)
    employer = models.CharField(max_length=20)

class Car(models.Model):
    person = models.ForeignKey(Person)
    name = models.CharField(max_length=10)
    model = models.CharField(max_length=10)
    ...

我想让所有拥有特定汽车的人:

people = Person.objects.filter(car__name="Toyota")

现在我想给这些人写下他们自己汽车的详细信息。我可以这样做:

for person in people:
   ...
   cars = person.car_set.filter(name="Toyota")
   ...

但它再次命中数据库。我怎样才能避免这种情况?有什么方法可以更简单吗?

【问题讨论】:

    标签: django django-models reverse-lookup


    【解决方案1】:

    车名时先选择车和相关人

    cars = Car.objects.select_related("person").filter(name="Toyota").order_by("person")
    

    现在您拥有所有名称为 toyota 的汽车以及该汽车的人,ordered_by person。

    现在使用 python itertools.groupby 为每个人分组这个列表

    from itertools import groupby
    for k, g in groupby(cars, lambda x: x.person):
           person = k
           cars = list(g)
    

    现在,在那个迭代中,你有了这个人和他的汽车(名字叫“toyota”)。 您会注意到只发生了单个查询,然后对缓存的信息执行以下操作。

    【讨论】:

    • 使用此技术的一个副作用是,如果您的人没有汽车,您将不会在该查询中看到这一点。这是因为查询是通过汽车域发起的。
    【解决方案2】:

    查看select_related(),我以前用过它,将许多跨多个模型的小查询变成一个大查询:https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related

    它通过预先填充QuerySet 来工作,因此您对car_set 的访问权已经存在,不会导致新的查询。

    【讨论】:

    • 即使我需要再次过滤它?我不想要每辆车,只想要丰田。
    • 如果您重复使用相同的QuerySet,它可能会起作用。查看:docs.djangoproject.com/en/dev/topics/db/queries/… 了解有关 QuerySet 缓存的更多详细信息。
    【解决方案3】:

    我不相信有任何办法可以避免额外的数据库命中。如果您担心查询过多,可以尝试以下方法:

    from collections import defaultdict
    
    cars = Car.objects.filter(**kwargs).selected_related('person')
    owners = defaultdict(list)
    
    for car in cars:
        owners[car.person].append(car)
    

    这应该只是一个选择所有相关汽车及其相关人员数据的查询

    【讨论】:

      猜你喜欢
      • 2014-02-16
      • 1970-01-01
      • 2013-02-24
      • 2016-08-31
      • 2018-10-15
      • 2011-05-09
      • 1970-01-01
      • 2014-10-03
      • 1970-01-01
      相关资源
      最近更新 更多