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


79

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

ps: Валюта НЕ заснована на доларі :)

Відповіді:


133

Завжди використовуйте DecimalFieldдля грошей. Навіть прості операції (додавання, віднімання) не захищені від проблем із округленням:

>>> 10.50 - 0.20
10.300000000000001

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

7
>>> 10.50 - 0.20в Python 2.7 отримати 10.3.
— Rockallite

6
Welp, лайно. Я перенесу багато даних із мого поля / стовпців FloatField у DecimalField ...
— teewuane

Висока час у нас є «не використовувати з плаваючою точкою для грошей» аналога в bobince в stackoverflow.com/a/1732454/604511
— Jesvin Хосе

@Rockallite - спробуйте 1.00 + 0.14, або "%.15f" % (10.5 - 0.2)- Проблема може бути затемнена через (я припускаю) bugs.python.org/issue1580 або щось подібне.
— Сет

@teewuane Чи не стикалися з якимись проблемами при перетворенні FloatField на DecimalField у вашому проекті Django? Я переробляю деякі старі проекти, які обробляють гроші, але заздалегідь використовую Float, OMG, Thx.
— Menglong Li

59

Відповідь на запитання правильна, однак деякі користувачі натраплять на це питання, щоб з’ясувати різницю між DecimalField та FloatField. Проблема округлення плаваючого потоку, яку піднімає Сет, є проблемою для валюти.

Держави Django Docs

Клас FloatField іноді змішується з класом DecimalField. Хоча вони обидва представляють дійсні числа, вони представляють ці числа по-різному. FloatField використовує внутрішній тип плаваючого Python, тоді як DecimalField використовує десятковий тип Python. Детальніше читайте тут .

Ось інші відмінності між двома полями:

Десяткове поле:

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

Детальніше про DecimalField із Django Docs .

FloatField:

  • Повертає вбудований тип float, <type 'float'>
  • Немає розумного округлення, і насправді може призвести до проблем із округленням, як описано у відповіді Seths.
  • Не має додаткової перевірки форми, яку ви отримуєте від DecimalField
  • У базі даних (postgresql) FloatField зберігається як тип "подвійної точності", а сховище встановлено як "звичайний"

Більше про FloatField із Документів Django .

Застосовується до обох:

  • Обидва поля поширюються від класу "Поле" і можуть приймати "порожнє", "нульове", "ім'я_дієслов'я", "ім'я", "основний_ключ", "макс. Атрибути ',' можна редагувати ',' серіалізувати ',' унікальний_на_дату ',' унікальний_на_місяць ',' унікальний_на_рік ',' вибір ',' довідковий_текст ',' db_column ',' db_tablespace ',' auto_created ',' валідатори ',' повідомлення про помилки ' , як і всі поля, що поширюються від "Поля".
  • Віджет форми за замовчуванням для обох полів - 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

Все це пов’язано з тим, як поплавок зберігається в пам’яті. Дивіться тут .


Здається, я завжди буду використовувати DecimalField над FloatField. Я не бачу жодної вигоди / простоти використання / простоти вибору FloatField під час обміну питаннями з округленням.
— Анкан-Зероб,

1
так DecimalField, якщо ви маєте справу з кінцевим набором десяткових знаків, наприклад, з валютою. Якщо ви хочете тип float, використовуйте FloatField (можливо, більш рідкісний випадок використання).
— radtek

9

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

Замість цього використовуйте ціле поле або рядок за вашим бажанням. Помножте свою валюту, щоб перемістити десятковий знак до кінця і складіть ціле число, коли ви його зберігаєте, а потім перемістіть цей десятковий знак назад туди, куди він належить, коли вам потрібно його показати. В основному це те, як банки (і більшість валютних бібліотек) обробляють дані, що позбавить вас багатьох проблем.

Я дізнався про це важко, бо це насправді не загальна тема; можливо, це рятує когось іншого від того самого.


7

редагувати: Проект Satchmo більше не активний, тому погляньте на ці альтернативи для обробки валюти


Проект Satchmo, що базується на Django, має CurrencyField і CurrencyWidget, на які варто поглянути.

Перевірте каталог додатка satchmo_utils для джерела

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.