2016-05-07 1 views
5

У меня есть этот код:Джанго F() деление - Как избежать округления

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() округленный результат? Как этого не сделать?

Спасибо!

+0

Вы пробовали 'float (F ('value1'))'? – trantu

+2

Вещь в выражениях 'F' заключается в том, что Python не знает о значениях, но передает эту операцию (деление в этом случае) в базу данных. Для PostgreSQL и MySQL целочисленное деление приводит к целому числу, как в Python 2.x – schwobaseggl

+0

Аргумент @trantu float() должен быть строкой или числом, а не 'F' – tim

ответ

3

Результат, которого вы ожидаете, очень легко достичь с помощью сырого запроса, и действительно, я имею в виду очень трудно достичь с чистым 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.

Чтобы предоставить некоторый фон. Округление выполняется с помощью базы данных, производящей целочисленное деление, потому что поле у ​​вас есть ints. Если вы хотите десятичное деление, вам нужно отбросить их на десятичные числа. К сожалению, с Django отличное отбрасывание.

Postgresql имеет действительно элегантный способ бросить плавать. value1 :: float, но этого нельзя использовать изнутри django (по крайней мере, насколько я знаю)

10

Просто используйте поддержку F() для умножения, чтобы преобразовать один коэффициент в десятичное число.

Комбинированное выражение тогда будет выглядеть так:

from decimal import Decimal 

q = MyModel.objects.order_by('-value1').annotate(
      res=ExpressionWrapper(
       (F('value1') * Decimal('1.0')/F('value2')), 
       output_field=FloatField()), 
      ) 

Я нахожу это более элегантный способ затем записать необработанный SQL CAST на поле значение1, а затем сделать разделение.

+0

Не пытайтесь найти ошибку (я дал вам возвышение), но это привело к тому, что TypeError: unbound method select_format() должен быть вызван с экземпляром FloatField в качестве первого аргумента (вместо этого был получен экземпляр SQLCompiler) – e4c5

+0

@ e4c5 Можете ли вы дать еще несколько конкретная информация (django ver, db, поддерживаемая и т. д.)? Я тестировал его с помощью Django 1.8 и Postgres, и он работает, как описано. Производит правильный SQL: 'django.db.connection [-1] ['sql'] == SELECT ... ((" shop_product "." Value1 "* 1.0) /" shop_product "." Value2 ") AS" res "FROM ... . 'res' содержит правильный десятичный результат, например 0.6666666666666666, когда value1 == 2 и value2 == 3. – joanbm

+0

django 1.9 postgresql 9.5 извините, я не могу воспроизвести ошибку сейчас, поскольку я не сохранил db – e4c5

 Смежные вопросы

  • Нет связанных вопросов^_^