Django Queryset с фильтрацией по обратному внешнему ключу - PullRequest
51 голосов
/ 25 марта 2011

У меня есть следующая модель Django:

class Make:
   name = models.CharField(max_length=200)

class MakeContent:
   make = models.ForeignKey(Make)
   published = models.BooleanField()

Я хотел бы знать, возможно ли (без написания SQL-кода напрямую) сгенерировать набор запросов, содержащий все Make s и каждый связанный MakeContent s, где published = True.

Ответы [ 4 ]

56 голосов
/ 26 марта 2011

Да, я думаю, что вы хотите

make = Make.objects.get(pk=1)
make.make_content_set.filter(published=True)

или, может быть,

make_ids = MakeContent.objects.filter(published=True).values_list('make_id', flat=True)
makes = Make.objects.filter(id__in=make_ids)
14 голосов
/ 03 апреля 2017

Я знаю, что это очень старый вопрос, но я отвечаю. Как я думаю, мой ответ может помочь другим. Я немного изменил модель следующим образом. Я использовал Django 1.8.

class Make(models.Model):
    name = models.CharField(max_length=200)

class MakeContent(models.Model):
    make = models.ForeignKey(Make, related_name='makecontent')
    published = models.BooleanField()

Я использовал следующий набор запросов.

Make.objects.filter(makecontent__published=True)

Надеюсь, это поможет.

14 голосов
/ 27 апреля 2013

Позвольте мне перевести ответ Спайка в коды для будущих зрителей. Обратите внимание, что каждое «Make» может иметь от нуля до нескольких «MakeContent»

Если спрашивающий хочет запросить «Сделать» с помощью В МЕДЛЕННО ОДНОМ «MakeContent», который опубликован = True, то второй фрагмент Джейсона Криста отвечает на вопрос.

Фрагмент эквивалентен

makes = Make.objects.select_related().filter(makecontent__published=True).distinct()

Но если спрашивающий хочет запросить «Make» с помощью ALL «MakeContent», который опубликован = True, то после вышеприведенных «make»,

import operator
make_ids = [m.id for m in makes if 
    reduce(operator.and_, [c.published for c in m.makecontent_set.all()] ) 
]
makes_query = Make.objects.filter(id__in=make_ids)

содержит требуемый запрос.

10 голосов
/ 25 марта 2011

Django не поддерживает метод select_related() для обратного поиска по внешнему ключу, поэтому лучшее, что вы можете сделать, не выходя из Python, - это два запроса к базе данных.Первый - захватить все Makes, которые содержат MakeContents, где published = True, а второй - захватить все MakeContents, где published = True.Затем вам нужно перебрать и расположить данные так, как вы хотите.Вот хорошая статья о том, как это сделать:

http://blog.roseman.org.uk/2010/01/11/django-patterns-part-2-efficient-reverse-lookups/

...