3

Django doc对聚合函数说:

output_field - 一个可选参数,表示返回值的模型字段

所以我希望下面的代码返回“True”。

MyModel.objects.annotate(foo=Max(Value("yes"), output_field=BooleanField())).first().foo

或者

MyModel.objects.annotate(foo=Max("id", output_field=BooleanField())).first().foo

但是在第一种情况下返回字符串“yes”,在第二种情况下返回一些整数。

我知道我可以使用“Cast”,但有人可以告诉我,在这种情况下,“output_field”有什么用处?

4

2 回答 2

0

在某些情况下,Django 需要明确知道某个字段中的数据类型。

例如,如果您尝试将此类查询集的结果提供给某个序列化程序(来自 Django REST 框架),您将收到错误并被迫提供输出字段。

于 2021-07-14T10:11:12.173 回答
0

搜索表达式的文档页面以查看许多示例:https ://docs.djangoproject.com/en/3.2/ref/models/expressions/

  • output_field如果 Django 没有足够的启发式方法来自行确定,则该参数用于解决表达式中的冲突或模棱两可的类型。
  • Djangooutput_field为你提供了一个路由来告诉它你真正想要的输出类型。
  • output_field参数不是为了让您转换值的类型,而是帮助 Django 在竞争选项中解析输出类型。
  • output_field参数并不总是必需的,但有时它会解决歧义,否则会导致 Django 引发异常。

看看你的例子,我只能假设 Djangooutput_field在这些情况下无视你。

关于两者输出的不同,Django 将裸字符串"id"视为字段名。如果您像“yes”一样使用字符串包裹"id"字符串,您会看到返回的是。如果您从示例中删除了包装器,您会看到:Value("id")"id"Value"yes"FieldError: Cannot resolve keyword 'yes' into field. Choices are: ...

作为一个更复杂的示例来说明output_field参数如何有用,请考虑 MS SQL Server,它没有适当的布尔类型,而是使用位字段来代替。

尝试 queryset = queryset.annotate( foo=Case(When(name__icontains='XYZ', then=Value(True)), default=Value(False)) ) 给出 django.core.exceptions.FieldError: Cannot resolve expression type, unknown output_field 即使您已经提交了两个明确的布尔值,Django 也找不到要返回的正确类型。

这就是output_field它的用途。您可以通过提供要使用的类型来解决 Django 的歧义: queryset = queryset.annotate( foo=Case(When(name__icontains='XYZ', then=Value(True)), default=Value(False), output_field=BooleanField()) ) 显然 Django 很乐意尝试,但无法在 MS SQL Server 下完成: django.db.utils.ProgrammingError: ('42000', '[42000] [FreeTDS][SQL Server]Statement(s) could not be prepared. (8180) (SQLExecDirectW)')

因此,要真正帮助 Django,您需要比 Django 了解更多 [原文如此] 并提供:(有效 queryset = queryset.annotate( foo=Case(When(name__icontains='XYZ', then=Value(True)), default=Value(False), output_field=BinaryField()) ) )。

将此应用于您的示例:MyModel.objects.annotate(foo=Max(False, output_field=BooleanField())).first().foo返回False

即使使用数值,Django 也能够根据您提供的output_field:MyModel.objects.annotate(foo=Max(0, output_field=BooleanField())).first().foo返回值来解释该值False

但正如我们所见,虽然 Django 可以处理这个问题,但 MS SQL Server 不会容忍布尔值,因为它没有布尔值;所以你可能会发现你需要在 MS SQL Server 的特定情况下执行此操作:MyModel.objects.annotate(foo=Max(0, output_field=BinaryField())).first().foo返回0.

因此,该output_field参数提供了这种额外的控制。

于 2021-11-08T07:43:02.830 回答