如何使用 Django 执行 __all_in 查询?

How to perform a __all_in query with Django?

我有三个模型

class Pizza(models.Model):
    toppings = models.ManyToManyField(Topping)

class Topping(models.Model):
    name = models.CharField(max_length=50)

class Order(models.Model):
    must_have_toppings = models.ManyToManyField(Topping)

我想找到与特定披萨匹配的所有订单。 为此,我想做一些像

orders = Order.objects.filter(must_have_toppings__all_in=my_pizza.toppings)

我尝试了什么:

orders = Order.objects.filter(must_have_toppings__in=my_pizza.toppings) 不起作用,因为 must_have 中只有一种披萨配料的订单将被 returned。

并且:

orders = Orders.objects
for topping in my_pizza.toppings.all():
    orders = orders.filter(must_have_toppings=topping)

不起作用,因为它将 return 包含比萨所有配料的订单,即使某些 must_have_toppings 缺失。例如,西红柿和蘑菇比萨将 return 需要西红柿、胡椒和蘑菇的订单。

如何查找 must_have_toppings 都在 Pizza 对象中的订单?

(我正在使用 MySql)

如果您想查找订单中所有 Topping 都属于 my_pizza 的订单,我们可以过滤:

from django.db.models import F, Q

toppings = my_pizza.toppings.all()

Order.objects.annotate(
    ntoppings=Count(
        'must_have_toppings',
        <strong>filter=Q(must_have_toppings__in=toppings)</strong>
    ),
    total=Count('must_have_toppings')
).filter(
    ntoppings=F('total')
)

我们这里先获取my_pizza的所有toppings,然后检查toppings的数量i是否与属于my_pizza的toppings的数量相同,如果成立,我们知道订单的所有浇头都是该披萨的成员。

我们也可以反其道而行之,检查 my_pizza 的所有浇头是否都属于 Order:

from django.db.models import Count, Q

toppings = my_pizza.toppings.all()
ntoppings = len(toppings)

Order.objects.annotate(
    ntoppings=Count(
        'must_have_toppings',
        <strong>filter=Q(must_have_toppings__in=toppings)</strong>
    )
).filter(
    ntoppings=ntoppings
)

如果 Order 的配料比比萨多,则该订单仍会显示。因此,如果比萨有奶酪和菠萝作为配料,那么奶酪、萨拉米香肠和菠萝的订单会匹配。

对于订单和 my_pizza 具有完全相同浇头的完全匹配,我们可以使用:

from django.db.models import Count, Q

toppings = my_pizza.toppings.all()
ntoppings = len(toppings)

Order.objects.annotate(
    ntoppings=Count(
        'must_have_toppings',
        <strong>filter=Q(must_have_toppings__in=toppings)</strong>
    ),
    total=Count('must_have_toppings')
).filter(
    ntoppings=ntoppings,
    total=ntoppings
)

所有代码片段都假定浇头只能发生一次。