如何在注解django中得到布尔结果?

py49o6xq  于 2023-03-13  发布在  Go
关注(0)|答案(2)|浏览(112)

我有一个过滤器,它应该返回一个查询集与2个对象,应该有一个不同的字段。例如:

obj_1 = (name='John', age='23', is_fielder=True)
obj_2 = (name='John', age='23', is_fielder=False)

两个对象的模型相同,但主键不同。我尝试使用以下筛选器:

qs = Model.objects.filter(name='John', age='23').annotate(is_fielder=F('plays__outdoor_game_role')=='Fielder')

我第一次使用annotate,但它给了我下面的错误:

TypeError: QuerySet.annotate() received non-expression(s): False.

我是Django的新手,那么我做错了什么,应该做什么注解才能得到如上所示的所需对象?

b1uwtaje

b1uwtaje1#

@ktowen的解决方案很好用,相当简单。这里是我正在使用的另一个解决方案,希望它也有帮助。

from django.db.models import BooleanField, ExpressionWrapper, Q

queryset = queryset.annotate(
    is_fielder=ExpressionWrapper(
        Q(plays__outdoor_game_role='Fielder'),
        output_field=BooleanField(),
    )
)

这里有一些解释给那些不熟悉Django ORM的人:

Annotate动态创建一个新的列/字段,在本例中为is_fielder。这意味着您的模型中没有名为is_fielder的字段,而在添加此“annotation”后,您可以像使用plays.outdor_game_role.is_fielder一样使用它。Annotate非常有用和灵活,几乎可以与任何其他表达式组合,应该是Django ORM中的一个MUST-KNOWN方法。
ExpressionWrapper基本上给了你空间来 Package 更复杂的条件组合,以ExpressionWrapper(expression, output_field)这样的格式使用。当你组合不同类型的字段或想要指定输出类型时,它很有用,因为Django不能自动判断。
Q object是一个经常用来指定条件的表达式,我认为最强大的部分是它可以链接条件:

1.与(&):filter(Q(condition1) & Q(condition2))
1.或(|):filter(Q(condition1) | Q(condition2))
1.阴性(~):filter(~Q(condition))
可以在如下正常条件下使用Q:(Q(condition1)|id__in=[list])
关键是Q对象必须先到达,否则它将不起作用。

**Case When(then)**可以简单地解释为if con1 elif con2 elif con3 ...,它相当强大,就我个人而言,我喜欢用它来为一个查询集定制一个排序对象。

例如,你需要返回一个观看历史条目的查询集,这些条目必须按照用户观看的顺序排列。你可以使用for循环来保持顺序,但这会生成大量类似的查询。使用Case When的一个更优雅的方法是:

from django.db.models import Case, Exists

item_ids = [list]
ordering = Case(*[
    When(pk=pk, then=pos)
    for pos, pk in enumerate(item_ids)
])
watch_history = Item.objects.filter(id__in=item_ids).order_by(ordering)

正如您所看到的,通过使用Case When(then),可以绑定那些非常具体的关系,可以将其视为1)精确的条件表达式,2)在连续多个条件的情况下特别有用。

3xiyfsfu

3xiyfsfu2#

可以将Case/Whenannotate一起使用

from django.db.models import Case, BooleanField, Value, When
Model.objects.filter(name='John', age='23').annotate(
    is_fielder=Case(
        When(plays__outdoor_game_role='Fielder', then=Value(True)),
        default=Value(False),
        output_field=BooleanField(),
    ),
)

相关问题