gpt4 book ai didi

django - 在 Django 的 ORM 中使用相同参数链接 Q() 对象时出现问题

转载 作者:行者123 更新时间:2023-12-04 14:22:16 24 4
gpt4 key购买 nike

我正在努力创建一个鸡尾酒食谱应用程序作为学习练习。

我正在尝试通过 Django 的 Rest 框架创建一个过滤器,该过滤器通过查询参数 (?=ingredients_exclusive=1,3,4) 接受一串成分 ID,然后搜索包含所有这些成分的所有食谱。我想搜索“所有含有朗姆酒和石榴糖浆的鸡尾酒”,然后分别搜索“所有含有朗姆酒和石榴汁的鸡尾酒”。

我的应用程序中的三个模型是 Recipes、RecipeIngredients 和 IngredientTypes。 Recipes (Old Fashioned) 有多个 RecipeIngredients(2oz of Whiskey),RecipeIngredients 都是一种 Ingredient Type(Whiskey)。我最终会将 RecipeIngredient 更改为 a through model取决于我决定走多远。

列表可以是可变长度的,所以我不能将过滤器函数链接在一起。我必须遍历 id 列表,然后构建一个 Q()。

但是,我遇到了一些问题。通过 Django Shell,我已经这样做了:

>>> x = Recipe.objects.all()
>>> q = Q(ingredients__ingredient_type=3) & Q(ingredients__ingredient_type=7)
>>> x.filter(q)
<QuerySet []>
>>> x.filter(ingredients__ingredient_type=3).filter(ingredients__ingredient_type=7)
<QuerySet [<Recipe: Rum and Tonic>]>

所以这是我的问题:为什么对两个查询进行 AND 操作的 Q 对象与同一对象的链式过滤器不同?

我已经通读了 Django 文档中的“Complex lookups with Q objects”,它似乎没有帮助。

仅供引用,这是我在 Filters.py 中的过滤器。

此命令的“或”版本工作正常:

class RecipeFilterSet(FilterSet):
ingredients_inclusive = django_filters.CharFilter(method='filter_by_ingredients_inclusive')
ingredients_exclusive = django_filters.CharFilter(method='filter_by_ingredients_exclusive')

def filter_by_ingredients_inclusive(self, queryset, name, value):
ingredients = value.split(',')
q_object = Q()
for ingredient in ingredients:
q_object |= Q(ingredients__ingredient_type=ingredient)
return queryset.filter(q_object).distinct()

def filter_by_ingredients_exclusive(self, queryset, name, value):
ingredients = value.split(',')
q_object = Q()
for ingredient in ingredients:
q_object &= Q(ingredients__ingredient_type=ingredient)
return queryset.filter(q_object).distinct()

class Meta:
model = Recipe
fields = ()

我还在下面包含了我的模型:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models


class IngredientType(models.Model):
name = models.CharField(max_length=256)

CATEGORY_CHOICES = (
('LIQUOR', 'Liquor'),
('SYRUP', 'Syrup'),
('MIXER', 'Mixer'),
)

category = models.CharField(
max_length=128, choices=CATEGORY_CHOICES, default='MIXER')

def __str__(self):
return self.name


class Recipe(models.Model):
name = models.CharField(max_length=256)

def __str__(self):
return self.name


class RecipeIngredient(models.Model):
ingredient_type = models.ForeignKey(IngredientType, on_delete=models.CASCADE, related_name="ingredients")
quantity = models.IntegerField(default=0)
quantity_type = models.CharField(max_length=256)
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE, related_name="ingredients")

@property
def ingredient_type_name(self):
return self.ingredient_type.name

@property
def ingredient_type_category(self):
return self.ingredient_type.category

def __str__(self):
return f'{self.quantity}{self.quantity_type} of {self.ingredient_type}'

非常感谢任何帮助!

最佳答案

filter() 的两种方法之间的区别在 Spanning multi-valued relationships 中有描述。 :

Everything inside a single filter() call is applied simultaneously to filter out items matching all those requirements.... For multi-valued relations, they apply to any object linked to the primary model, not necessarily those objects that were selected by an earlier filter() call.

文档中的示例使其更加清晰。我会根据您的问题重写它:

To select all recipes that contain an ingredient with both type 3 and type 7, we would write:

Recipe.objects.filter(ingredients__ingredient_type=3, ingredients__ingredient_type=7)

这在您的模型中当然是不可能的,因此这将返回一个空的查询集,就像您使用 ANDQ 示例一样。

To select all recipes that contain an ingredient with type 3 as well as an ingredient with type 7, we would write:

Recipe.objects.filter(ingredients__ingredient_type=3).filter(ingredients__ingredient_type=7)

这不是特别直观,但他们需要一种方法来区分这两种情况,这就是他们想出的方法。


回到您的问题,OR 的情况可以通过使用 in 运算符变得更简单:

Recipe.objects.filter(ingredients__ingredient_type__in=[3, 7]).distinct()

AND 的情况很复杂,因为它是一个涉及多行的条件。一种简单的方法是只采用上面的 OR 版本并在 Python 中进一步处理它以找到包含所有成分的子集。

应该工作的查询方法涉及注释 Count .这是未经测试的,但类似于:

Recipe.objects.annotate(num_ingredients=Count("ingredients", 
filter=Q(ingredients__ingredient_type__in=[3, 7]))
.filter(num_ingredients=2)

关于django - 在 Django 的 ORM 中使用相同参数链接 Q() 对象时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53027017/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com