@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对象是一个常用的表达式来指定一个条件,我认为最强大的部分是可以链接条件:
- 与 (&):
filter(Q(condition1) & Q(condition2))
- 或(|):
filter(Q(condition1) | Q(condition2))
- 负(~):
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)在顺序多条件情况下特别有用。