Джанго - обратный поиск - PullRequest
2 голосов
/ 08 июля 2011

Например, у меня есть эти модели:

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")
   ...

Но это следующий удар по базе данных.Как я могу избежать этого?Есть ли способ сделать это проще?

Ответы [ 3 ]

3 голосов
/ 10 июля 2011

Сначала выберите автомобиль и связанное с ним лицо, когда имя машины

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

Теперь у вас есть все машины, чье имя - toyota, а также лицо для этого автомобиля, order_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").Вы заметите, что выполняется только один запрос, а затем выполняются следующие операции с кэшированной информацией.

0 голосов
/ 08 июля 2011

Я не верю, что в любом случае можно избежать дополнительных попаданий в базу данных.Если вас беспокоит слишком большое количество запросов, вы можете попробовать что-то вроде этого:

from collections import defaultdict

cars = Car.objects.filter(**kwargs).selected_related('person')
owners = defaultdict(list)

for car in cars:
    owners[car.person].append(car)

Это должен быть только один запрос, который выбирает все релевантные автомобили и данные об их человеке

0 голосов
/ 08 июля 2011

Извлеките select_related(), я использовал его раньше, чтобы превратить множество небольших запросов, охватывающих несколько моделей, в один большой запрос: https://docs.djangoproject.com/en/dev/ref/models/querysets/#select-related

Это работает, предварительно заполнив QuerySet, поэтому ваш доступ к car_set уже будет там и не приведет к новому запросу.

...