Подтвердить что ты не робот

Django: FloatField или DecimalField для валюты?

Мне любопытно, какой из них лучше подходит как валютное поле? Я буду делать простые операции, такие как различие, процент между старыми и новыми ценами. Я планирую сохранить две цифры после нуля (т.е. 10.50) и большую часть времени, если эти цифры равны нулю, я буду скрывать эти цифры и отображать их как "10"

ps: Валюта не основана на долларах:)

4b9b3361

Ответ 1

Всегда используйте DecimalField за деньги. Даже простые операции (сложение, вычитание) не защищены от проблем округления округления:

>>> 10.50 - 0.20
10.300000000000001

>>> Decimal('10.50') - Decimal('0.20')
Decimal('10.30')

Ответ 2

Ответ на вопрос правильный, однако некоторые пользователи могут наткнуться на этот вопрос, чтобы выяснить разницу между DecimalField и FloatField. Проблема округления чисел, которую поднимает Сет, является проблемой для валюты.

Государства Django Docs

Класс FloatField иногда смешивается с классом DecimalField. Хотя они оба представляют действительные числа, они представляют эти числа по-разному. FloatField использует тип чисел с плавающей точкой Pythons, а DecimalField использует десятичный тип Pythons. Подробнее здесь.

Вот другие различия между этими двумя полями:

DecimalField:

  • DecimalFields должен определять атрибуты "decimal_places" и "max_digits".
  • Вы получаете две бесплатные проверки формы, включенные здесь из вышеуказанных обязательных атрибутов, т.е. если вы установите max_digits равным 4 и введете десятичное число, равное 4,00000 (5 цифр), вы получите эту ошибку: Убедитесь, что не более 4 Всего цифр.
  • Вы также получаете аналогичную проверку формы, выполненную для десятичных разрядов (которая в большинстве браузеров также будет проверяться во внешнем интерфейсе с использованием атрибута step в поле ввода. Если вы установите decimal_places = 1 и введите 0,001 в качестве значения, вы получите ошибку минимальное значение должно быть 0,1.
  • Возвращает десятичное число. Десятичное число, тип <class 'decimal.Decimal'>
  • Не имеет дополнительной проверки как DecimalField
  • Для типа Decimal округление также выполняется для вас из-за обязательных атрибутов, которые необходимо установить, как описано выше. Так что из оболочки, если вы
  • В базе данных (postgresql) поле DecimalField сохраняется в виде числового типа (max_digits, decimal_laces), а для хранилища задано значение "main", из приведенного выше примера тип является числовым (4,1)

Подробнее о DecimalField из Django Docs.

FloatField:

  • Возвращает встроенный тип с плавающей точкой, <type 'float'>
  • Нет умного округления, и может привести к проблемам округления, как описано в ответе Сета.
  • Не имеет дополнительной проверки формы, которую вы получаете из DecimalField
  • В базе данных (postgresql) FloatField сохраняется как тип "двойной точности", а хранилище - как "обычный"

Подробнее о FloatField из Django Docs.

Относится к обоим:

  • Оба поля выходят из класса "Field" и могут принимать "пусто", "null", "verbose_name", "name", "primary_key", "max_length", "unique", "db_index", "rel", "default" Атрибуты ',' editable ',' serialize ',' unique_for_date ',' unique_for_month ',' unique_for_year ',' choices ',' help_text ',' db_column ',' db_tablespace ',' auto_created ',' validators ',' error_messages ', как и все поля, которые выходят из "поля".
  • Виджет формы по умолчанию для обоих полей - TextInput.

Я сталкивался с этим вопросом, когда искал разницу между двумя полями, поэтому думаю, что это поможет тем, кто находится в одной и той же ситуации :)

ОБНОВЛЕНИЕ: Чтобы ответить на вопрос, я думаю, что вы можете выбрать любой из них для представления валюты, хотя десятичная дробь гораздо лучше подходит. Существует проблема с округлением, когда он считается с плавающей точкой, поэтому вы должны использовать round(value, 2), чтобы сохранить представление с плавающей точкой округленным до двух десятичных разрядов. Вот быстрый пример:

>>> round(1.13 * 50 + .01, 2)
56.51

У тебя все еще могут быть проблемы с поплавком и раундом. Например, здесь мы видим округление до значения 5:

>>> round(5.685, 2)
5.68

Но в этом случае он будет округляться:

>>> round(2.995, 2)
3.0

Это связано с тем, как поплавок хранится в памяти. Смотрите здесь.

Ответ 3

edit: Проект Satchmo больше неактивен, поэтому взгляните на эти альтернативы для обработки валюты


Проект Satchmo на основе Django имеет вид CurrencyField и CurrencyWidget, на который стоит обратить внимание.

Откройте каталог приложений satchmo_utils для источника

Ответ 4

Я знаю, что это очень старое, но я наткнулся на это в поисках чего-то совершенно другого, и я хотел бы добавить, что в общем случае не рекомендуется использовать числа с плавающей запятой (с плавающей запятой или десятичное число) для валюты, поскольку математическое округление с плавающей запятой будет неизменно приводят к небольшим ошибкам в расчетах, которые со временем могут привести к очень большим расхождениям.

Вместо этого используйте целочисленное поле или строку по своему усмотрению. Умножьте свою валюту, чтобы переместить десятичную запятую в конец, и сделайте целое число, когда вы сохраните ее, а затем переместите ту десятичную запятую туда, где она должна быть, когда вам нужно ее показать. Это в основном то, как банки (и большинство библиотек валют) обрабатывают хранение данных и в дальнейшем избавят вас от проблем.

Я научился этому нелегко, потому что это не совсем обычная тема; может быть, это спасает кого-то еще от того же.