Django F () division - как избежать округления
у меня есть этот код:
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 () округленный результат? Как не сделать этого?
спасибо!
3 ответов
результат, который вы ожидаете, очень легко достичь с помощью raw-запроса и действительно, я имею в виду очень трудно достичь с чистым 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.
чтобы обеспечить некоторый фон. Округление выполняется базой данных doing целочисленное деление потому что поле у вас есть ints. Если вы хотите десятичное деление, вам нужно привести их к десятичным дробям. К сожалению, литье не очень легко с Django.
Postgresql имеет действительно элегантный способ бросить плавать. value1:: float но это нельзя использовать изнутри django (по крайней мере, насколько я знаю)
просто использовать F()
поддержка умножения для преобразования одного фактора в десятичное число.
комбинированное выражение тогда будет выглядеть так:
from decimal import Decimal
q = MyModel.objects.order_by('-value1').annotate(
res=ExpressionWrapper(
(F('value1') * Decimal('1.0') / F('value2')),
output_field=FloatField()),
)
Я нахожу этот более элегантный способ, затем пишу raw SQL CAST на поле value1, а затем делаю разделение.
к сожалению, 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(),
),
)
)