Django Query Многие отношения «включают»

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

class Contact(models.Model):
    email_list = models.ForeignKey(EmailList, related_name='contacts')
    customer = models.ForeignKey('Customer')

class EmailList(models.Model):
    customers = models.ManyToManyField('Customer',
        related_name='lists',
        through='Contact')

class Customer(models.Model):
    email = models.EmailField(max_length=255, unique=True)

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

all_customers.filter(lists__id__contains=[email_list_1.pk, email_list_2.pk])

это странно, но я принимаю и возвращаю пустой набор запросов, но что удивляет, так это то, что он работает, когда запрашивает только 1 EmailList, например:

all_customers.filter(lists__id__contains=email_list_1.pk)

Итак, мой следующий шаг - запрос с помощью оператора AND

customers.filter(Q(lists__id__contains=el1.pk) & Q(lists__id__contains=el2.pk))

но это возвращает и пустой QuerySet. Я хотел бы найти способ, чтобы иметь возможность запрашивать lists__id__contains передачу итерируемого идентификатора, или, по крайней мере, найти способ объединить подзапросы

Всего 1 ответ


Причина этого заключается в том, что поиск __contains [Django-doc] работает для текста, и если правый операнд не является строкой, он преобразует его в строку. Таким образом, вы в основном запрашиваете что-то, что имеет в качестве подстроки '[1, 4]'1 и 4 идентификаторами они могут быть разными).

Клиент находится в любом из списков

Вам нужно использовать __in lookup [Django-doc] здесь:

all_customers.filter(lists__id__in=[email_list_1.pk, email_list_2.pk])

или вы можете использовать «логический или»:

customers.filter(Q(lists__id=el1.pk) | Q(lists__id=el2.pk))

Клиент во всех списках

Кроме того, мы можем запрашивать клиентов, которые есть во всех списках, путем аннотирования и фильтрации:

ids = [email_list_1.pk, email_list_2.pk]

all_customers.filter(lists__id__in=ids).annotate(
    nlists=Count('lists')
).filter(
    nlists=len(set(ids))
)

Есть идеи?

10000