Kes*_*iya 1 django django-queryset django-rest-framework
我有一个过滤器,它应该返回一个包含 2 个对象的查询集,并且应该有一个不同的字段。例如:
obj_1 = (name='John', age='23', is_fielder=True)
obj_2 = (name='John', age='23', is_fielder=False)
Run Code Online (Sandbox Code Playgroud)
两个对象具有相同的模型,但主键不同。我尝试使用以下过滤器:
qs = Model.objects.filter(name='John', age='23').annotate(is_fielder=F('plays__outdoor_game_role')=='Fielder')
Run Code Online (Sandbox Code Playgroud)
我第一次使用注释,但它给了我以下错误:
TypeError: QuerySet.annotate() received non-expression(s): False.
Run Code Online (Sandbox Code Playgroud)
我是 Django 新手,所以我做错了什么,应该使用什么注释来获取如上所示的所需对象?
@ktowen 的解决方案效果很好,非常简单。这是我正在使用的另一个解决方案,希望它也有帮助。
from django.db.models import BooleanField, ExpressionWrapper, Q
queryset = queryset.annotate(
is_fielder=ExpressionWrapper(
Q(plays__outdoor_game_role='Fielder'),
output_field=BooleanField(),
)
)
Run Code Online (Sandbox Code Playgroud)
对于那些不熟悉 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的更优雅的方式是:
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)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,通过使用Case When(then)可以绑定那些非常具体的关系,这可以被视为 1) 精确/精确的条件表达式,2) 在连续的多个条件情况下特别有用。
小智 6
您可以Case/When使用annotate
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(),
),
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2672 次 |
| 最近记录: |