【问题标题】:How to get boolean result in annotate django?如何在annotate django中获得布尔结果?
【发布时间】:2020-07-20 15:16:53
【问题描述】:

我有一个过滤器,它应该返回一个包含 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')

我第一次使用注释,但它给了我以下错误:

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

我是 Django 新手,我做错了什么,如上所示,获取所需对象的注释应该是什么?

【问题讨论】:

    标签: django django-rest-framework django-queryset


    【解决方案1】:

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

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

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

    注释动态创建一个新列/字段,在本例中为is_fielder。这意味着您的模型中没有名为 is_fielder 的字段,而在添加此“注释”后,您可以像 plays.outdor_game_role.is_fielder 一样使用它。 Annotate 非常有用和灵活,可以与几乎所有其他表达式组合,应该是 Django ORM 中必须知道的方法。

    ExpressionWrapper 基本上为您提供空间来包装更复杂的条件组合,以ExpressionWrapper(expression, output_field) 之类的格式使用。当您组合不同类型的字段或想要指定输出类型时,它很有用,因为 Django 无法自动判断。

    Q对象是一个常用的表达式来指定一个条件,我认为最强大的部分是可以链接条件:

    1. 与 (&):filter(Q(condition1) & Q(condition2))
    2. 或(|):filter(Q(condition1) | Q(condition2))
    3. 负(~):filter(~Q(condition))

    可以在正常情况下使用 Q,如下所示: (Q(condition1)|id__in=[list])

    重点是Q对象一定要先来,不然不行。

    Case When(then) 可以简单地解释为if con1 elif con2 elif con3 ...。它非常强大,我个人喜欢用它来为查询集自定义排序对象。

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

    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)在顺序多条件情况下特别有用。

    【讨论】:

      【解决方案2】:

      您可以将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(),
          ),
      )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-12
        • 1970-01-01
        • 1970-01-01
        • 2011-10-02
        • 2020-08-07
        相关资源
        最近更新 更多