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.