У меня есть модели с отношениями "многие ко многим", например:
class Contact(models.Model):
name = models.TextField()
address = models.TextField()
class Mail(models.Model):
to = models.ManyToManyField(Contact, related_name='received_mails')
cc = models.ManyToManyField(Contact, related_name='cced_mails')
Я хочу получить набор контактов, которые находятся либо в поле to, либо в cc поле для данного адреса электронной почты. Попробуем:
>>> Contact.objects.filter(received_mails__id=111)
[<Contact: fred@foo.com>]
>>> Contact.objects.filter(cced_mails__id=111)
[<Contact: joe@bar.com>]
Пока все хорошо. У нас есть одно контактное лицо для каждого отношения. Но было бы неплохо поместить их в один и тот же QuerySet.
>>> Contact.objects.filter(Q(received_mails__id=111) | Q(cced_mails__id=111))
[<Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, <Contact: joe@bar.com>, '...(remaining elements truncated)...']
Что случилось? У меня есть ощущение, что это как-то связано с объединением таблиц в SQL, но я действительно не понимаю, что происходит под капотом со многими отношениями. Может быть, то, что я пытаюсь сделать, глупо, или есть простой способ сделать это. В любом случае, я счастлив, что встал на правильный путь.
Edit: это запрос QuerySet:
SELECT `mailshareapp_contact`.`id`, `mailshareapp_contact`.`name`,
`mailshareapp_contact`.`address` FROM `mailshareapp_contact`
LEFT OUTER JOIN `mailshareapp_mail_to`
ON (`mailshareapp_contact`.`id` = `mailshareapp_mail_to`.`contact_id`)
LEFT OUTER JOIN `mailshareapp_mail_cc`
ON (`mailshareapp_contact`.`id` = `mailshareapp_mail_cc`.`contact_id`)
WHERE (`mailshareapp_mail_to`.`mail_id` = 111
OR `mailshareapp_mail_cc`.`mail_id` = 111 )