Django исключает набор запросов __in для * каждого * элемента в списке

Это немного отличается от Django filter queryset __in для *каждого* элемент в списке и Django filter набор запросов __in для *каждого* элемента в списке (2.0) Учитывая следующие модели:

class Product(BaseModel):
    ''' whatever '''

class Customer(BaseModel):
    blacklist = models.ManyToManyField(Product, blank=True)

class Advisory(BaseModel):
    product_names = models.ManyToManyField(Product)

Где клиент ведет список продуктов, которые его не интересуют. Как я могу получить список рекомендаций для данного клиента?

Скажем, у меня есть это в моей БД:

#   Advisory 1 (should be included as Product 1 isn't in the customers blacklist)
#       product_names
#           Product 1
#           Product 2
#           Product 3
#   Advisory 2 (should be excluded)
#       product_names
#           Product 2
#           Product 3
#   Customer 1
#       blacklist
#           Product 2
#           Product 3
#           Product 4
#           Product 5

Если я использую такой набор запросов:

queryset = Advisory.objects.all()
blacklist = Customer.blacklist.all()
queryset = queryset.exclude(product_names__in=blacklist).distinct()

Он исключит как рекомендацию 1, так и рекомендацию 2, поскольку продукт 2 и 3 присутствуют в черном списке клиентов.


person TheStigmj    schedule 22.05.2018    source источник
comment
Итак, вам нужны только те рекомендации, у которых есть по крайней мере один product, которого нет в blacklist?   -  person Willem Van Onsem    schedule 22.05.2018
comment
Да, это правильно.   -  person TheStigmj    schedule 22.05.2018
comment
По сути, здесь вам нужен NOT IN, которого явно не хватает в Django. .exclude на самом деле не равно NOT IN, так как это означает NOT IN для всего отношения.   -  person Willem Van Onsem    schedule 22.05.2018


Ответы (1)


Я нашел решение проблемы, выполнив ее в два этапа:

# Get the queryset with all advisories
queryset = Advisory.objects.all()
# Find the products the customer doesn't care about
blacklist = Customer.objects.get(pk=customer_id).blacklist.all()
# Build a whitelist of products excluding the blacklist from the customer
whitelist = Product.objects.all().exclude(id__in=blacklist)
# And filter the queryset with the new whitelist
queryset = queryset.filter(product_names__in=whitelist).distinct()
person TheStigmj    schedule 22.05.2018