使用 Django 的 ORM 进行复杂的 M2M 过滤
Complex M2M filtering using Django's ORM
我有以下型号:
class Sauce(models.Model):
...
class Topping(models.Model):
...
class Pizza(models.Model):
sauces = models.ManyToManyField(Sauce, related_name='pizzas')
toppings = models.ManyToManyField(Topping, related_name='pizzas')
现在,假设我想在给定浇头和酱汁列表的情况下查询所有比萨饼。例如:
sauces_ids = [1, 2]
toppings_ids = [1, 2]
我现在在 API 视图中所做的如下:
pizzas = Pizza.objects.filter(restaurant=restaurant)
if request.data.get('sauces_ids', []):
pizzas = pizzas.filter(
sauces__in=
request.data['sauces_ids']
)
if request.data.get('toppings_ids', []):
pizzas = pizzas.filter(
toppings__in=
request.data['toppings_ids']
)
return pizzas.distinct()
我使用 distinct()
函数解决了一个重复问题。但是,现在我面临着一个不同的问题。我的数据库中有 2 个比萨饼:
- 带酱汁的披萨 1 = [1, 2],配料 = [1, 2]
- 带酱汁的披萨 2 = [1, 2],配料 = [1]
使用上述查询参数,我只想 return 披萨 1,因为 2 个 M2M 列表完全匹配。但是,我写的查询是 returning 两个比萨饼。我该如何解决这个问题?感谢您的帮助。
此外,这是一种有效的方法吗?
这是因为您正在执行的查询将 return 具有浇头 1 或浇头 2 AND 酱汁 1 或酱汁 2 的比萨饼。
因为比萨 1 有浇头 1 和 2,酱汁 1 和 2 你明白了。
因为比萨 2 有浇头 1,酱汁 1 和 2,所以你明白了。
基本上,如果我没记错的话你可以这样做:
pizzas = Pizza.objects.filter(restaurant=restaurant)
if request.data.get('sauces_ids', []):
sauces = request.data.get('sauces_ids'):
for sauce in sauces:
pizzas = pizzas.filter(
sauces__pk=sauce
)
if request.data.get('toppings_ids', []):
toppings = request.data.get('toppings_ids'):
for topping in toppings:
pizzas = pizzas.filter(
toppings__pk=topping
)
return pizzas.distinct()
我不太担心效率,因为 QuerySets 是惰性的,即使您的 sauces/topping 列表很大,您最终也会执行少量查询
我有以下型号:
class Sauce(models.Model):
...
class Topping(models.Model):
...
class Pizza(models.Model):
sauces = models.ManyToManyField(Sauce, related_name='pizzas')
toppings = models.ManyToManyField(Topping, related_name='pizzas')
现在,假设我想在给定浇头和酱汁列表的情况下查询所有比萨饼。例如:
sauces_ids = [1, 2]
toppings_ids = [1, 2]
我现在在 API 视图中所做的如下:
pizzas = Pizza.objects.filter(restaurant=restaurant)
if request.data.get('sauces_ids', []):
pizzas = pizzas.filter(
sauces__in=
request.data['sauces_ids']
)
if request.data.get('toppings_ids', []):
pizzas = pizzas.filter(
toppings__in=
request.data['toppings_ids']
)
return pizzas.distinct()
我使用 distinct()
函数解决了一个重复问题。但是,现在我面临着一个不同的问题。我的数据库中有 2 个比萨饼:
- 带酱汁的披萨 1 = [1, 2],配料 = [1, 2]
- 带酱汁的披萨 2 = [1, 2],配料 = [1]
使用上述查询参数,我只想 return 披萨 1,因为 2 个 M2M 列表完全匹配。但是,我写的查询是 returning 两个比萨饼。我该如何解决这个问题?感谢您的帮助。
此外,这是一种有效的方法吗?
这是因为您正在执行的查询将 return 具有浇头 1 或浇头 2 AND 酱汁 1 或酱汁 2 的比萨饼。
因为比萨 1 有浇头 1 和 2,酱汁 1 和 2 你明白了。
因为比萨 2 有浇头 1,酱汁 1 和 2,所以你明白了。
基本上,如果我没记错的话你可以这样做:
pizzas = Pizza.objects.filter(restaurant=restaurant)
if request.data.get('sauces_ids', []):
sauces = request.data.get('sauces_ids'):
for sauce in sauces:
pizzas = pizzas.filter(
sauces__pk=sauce
)
if request.data.get('toppings_ids', []):
toppings = request.data.get('toppings_ids'):
for topping in toppings:
pizzas = pizzas.filter(
toppings__pk=topping
)
return pizzas.distinct()
我不太担心效率,因为 QuerySets 是惰性的,即使您的 sauces/topping 列表很大,您最终也会执行少量查询