Django F() 除法 - 如何避免四舍五入
Django F() division - How to avoid rounding off
我有这个代码:
q = MyModel.objects.order_by('-value1').annotate(
res=ExpressionWrapper(
(F('value1') / F('value2')),
output_field=FloatField()),
)
for i in q:
print(i.value1, i.value2, i.res)
因此,输出将是:
5 10 0.0
1 2 0.0
但我需要
5 10 0.5
1 2 0.5
Wy F() 四舍五入结果?如何不这样做?
谢谢!
只需利用F()
对乘法的支持将一个因数转换为十进制数。
组合表达式将如下所示:
from decimal import Decimal
q = MyModel.objects.order_by('-value1').annotate(
res=ExpressionWrapper(
(F('value1') * Decimal('1.0') / F('value2')),
output_field=FloatField()),
)
我发现这种更优雅的方式然后在 value1 字段上写入原始 SQL CAST,然后进行除法。
您期望的结果很容易通过原始查询实现,我的意思是,使用纯 Django 很难实现。
from django.db.models import FloatField, ExpressionWrapper, F
template = '%(function)s(%(expressions)s AS FLOAT)'
fv1 = Func(F('value1'), function='CAST', template=template)
fv2 = Func(F('value2'), function='CAST', template=template)
ew = ExpressionWrapper(fv1/fv2, output_field = FloatField())
q = MyModel.objects.order_by('-value1').annotate(res = ew)
您不会指责它优雅,但它适用于 Mysql 和 Postgresql。
提供一些背景知识。四舍五入是由数据库执行 整数除法 完成的,因为您拥有的字段是整数。如果你想要小数除法,你需要将它们转换为小数。不幸的是,使用 Django 进行转换并不是很容易。
Postgresql 有一种非常优雅的方式转换为浮动。 value1::float 但这不能从 django 内部使用(至少据我所知)
不幸的是,ORM F('value1') / F('value2')
操作是在数据库端执行的,因此如果两个字段都声明为 integer
,您肯定会得到 integer
结果。在 Django 1.11.7 中,您可以像这样简单地将 F()
表达式之一转换为 decimal
:
qs = (
MyModel.objects
.annotate(
res=ExpressionWrapper(
F('value1') * 1.0 / F('value2'),
output_field=FloatField(),
),
)
)
在 v1.10 中,Django 引入了一个 Cast function which makes this (almost) a breeze – the qualification being that you either need two casts or need to wrap the whole thing in an ExpressionWrapper 来避免 FieldError: Expression contains mixed types. You must set output_field.
q = MyModel.objects.annotate(
res=ExpressionWrapper(
(Cast('value1', FloatField()) / F('value2')),
output_field=FloatField()),
)
这在功能上等同于将枚举数乘以 1.0
,但显式转换比乘以数字更清楚您的意图。
我有这个代码:
q = MyModel.objects.order_by('-value1').annotate(
res=ExpressionWrapper(
(F('value1') / F('value2')),
output_field=FloatField()),
)
for i in q:
print(i.value1, i.value2, i.res)
因此,输出将是:
5 10 0.0
1 2 0.0
但我需要
5 10 0.5
1 2 0.5
Wy F() 四舍五入结果?如何不这样做?
谢谢!
只需利用F()
对乘法的支持将一个因数转换为十进制数。
组合表达式将如下所示:
from decimal import Decimal
q = MyModel.objects.order_by('-value1').annotate(
res=ExpressionWrapper(
(F('value1') * Decimal('1.0') / F('value2')),
output_field=FloatField()),
)
我发现这种更优雅的方式然后在 value1 字段上写入原始 SQL CAST,然后进行除法。
您期望的结果很容易通过原始查询实现,我的意思是,使用纯 Django 很难实现。
from django.db.models import FloatField, ExpressionWrapper, F
template = '%(function)s(%(expressions)s AS FLOAT)'
fv1 = Func(F('value1'), function='CAST', template=template)
fv2 = Func(F('value2'), function='CAST', template=template)
ew = ExpressionWrapper(fv1/fv2, output_field = FloatField())
q = MyModel.objects.order_by('-value1').annotate(res = ew)
您不会指责它优雅,但它适用于 Mysql 和 Postgresql。
提供一些背景知识。四舍五入是由数据库执行 整数除法 完成的,因为您拥有的字段是整数。如果你想要小数除法,你需要将它们转换为小数。不幸的是,使用 Django 进行转换并不是很容易。
Postgresql 有一种非常优雅的方式转换为浮动。 value1::float 但这不能从 django 内部使用(至少据我所知)
不幸的是,ORM F('value1') / F('value2')
操作是在数据库端执行的,因此如果两个字段都声明为 integer
,您肯定会得到 integer
结果。在 Django 1.11.7 中,您可以像这样简单地将 F()
表达式之一转换为 decimal
:
qs = (
MyModel.objects
.annotate(
res=ExpressionWrapper(
F('value1') * 1.0 / F('value2'),
output_field=FloatField(),
),
)
)
在 v1.10 中,Django 引入了一个 Cast function which makes this (almost) a breeze – the qualification being that you either need two casts or need to wrap the whole thing in an ExpressionWrapper 来避免 FieldError: Expression contains mixed types. You must set output_field.
q = MyModel.objects.annotate(
res=ExpressionWrapper(
(Cast('value1', FloatField()) / F('value2')),
output_field=FloatField()),
)
这在功能上等同于将枚举数乘以 1.0
,但显式转换比乘以数字更清楚您的意图。