Многие ко многим запросам: найти слова, которые проверяли только фразы
Я имею word
модель и phrase
модель
class Word(models.Model):
checked = models.BooleanField(default=False)
class Phrase(models.Model):
words = models.ManyToManyField(Word, null=True,related_name = "phrases")
Word
модель имеет атрибут checked
и много ко многим подключение к phrase
Мне нужно выполнить сложный для меня запрос:
Мы рассматриваем эту фразу
is checked
если есть хотя бы одинchecked
слово.Как найти все слова, которые только проверяли фразы и не имеют
unchecked
фразы?
Прямо сейчас я использую цикл по всем словам в БД, но это не очень эффективно, поэтому я ищу более эффективный способ сделать это.
1 ответ
Мы можем сделать это в два этапа:
non_checked_phrases=Phrase.objects.exclude(word__checked=True)
non_checked_words = Word.objects.exclude(phrases__in=non_checked_phrases)
Сначала мы таким образом получаем QuerySet
из Phrases
где никакие из связанных слов не проверены. Далее мы получаем QuerySet
где мы исключаем все слова, которые имеют связанную фразу в ранее сгенерированном QuerySet
,
Это сгенерирует запрос как:
SELECT word.*
FROM word
WHERE NOT (word.id IN
(SELECT pw1.`word_id`
FROM phrase_word AS pw1
WHERE pw1.phrase_id IN
(SELECT p.`id`
FROM `auth_group` AS p
WHERE NOT (V0.`id` IN
(SELECT pw2.`phrase_id`
FROM phrase_word AS pw2
INNER JOIN word AS w2 ON pw2.word_id = w2.id
WHERE w2.is_active = True
)
))
)
)