Многие ко многим запросам: найти слова, которые проверяли только фразы

Я имею 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
             )
         ))
    )
)
Другие вопросы по тегам