Django: FloatField of DecimalField voor valuta?

Ik ben benieuwd welke beter zou passen als valutaveld? Ik zal eenvoudige bewerkingen doen, zoals het nemen van verschil, het percentage tussen oude en nieuwe prijzen. Ik ben van plan om twee cijfers na de nul te behouden (dwz 10,50) en als deze cijfers nul zijn, zal ik deze cijfers verbergen en weergeven als “10”

ps: Valuta is NIET gebaseerd op dollars 🙂


Antwoord 1, autoriteit 100%

Gebruik altijd DecimalFieldvoor geld. Zelfs eenvoudige bewerkingen (optellen, aftrekken) zijn niet immuun voor problemen met zwevende afronding:

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

Antwoord 2, autoriteit 48%

Het antwoord op de vraag is correct, maar sommige gebruikers zullen op deze vraag stuiten om het verschil te ontdekken tussen het DecimalFielden het FloatField. Het vlotter-afrondingsprobleem dat Seth ter sprake brengt, is een probleem voor valuta.

De Django Docs-staten

De klasse FloatFieldwordt soms verward met de klasse DecimalField. Hoewel ze allebei reële getallen vertegenwoordigen, vertegenwoordigen ze die getallen anders. FloatFieldgebruikt het float-type van Python intern, terwijl DecimalFieldhet Decimal-type van Python gebruikt.

Lees hier.

Hier zijn andere verschillen tussen de twee velden:

Decimaalveld:

  • DecimalFields moeten een decimal_placesen een max_digits-attribuut definiëren.
  • U krijgt hier twee gratis formuliervalidaties van de bovenstaande vereiste kenmerken, bijv. als u max_digitsinstelt op 4, en u typt een decimaalteken dat 4.00000(5 cijfers) is, krijgt u deze foutmelding: Zorg ervoor dat er zijn in totaal niet meer dan 4 cijfers.
  • Je krijgt ook een vergelijkbare vormvalidatie voor decimalen (die in de meeste browsers ook aan de voorkant valideert met behulp van het step-attribuut in het invoerveld. Als je decimal_places = 1instelt en typt in 0.001als de waarde krijgt u een foutmelding dat de minimumwaarde 0.1moet zijn.
  • Retourneert een decimal.Decimal, type is <class 'decimal.Decimal'>
  • Heeft niet de extra validatie van DecimalField
  • Bij een Decimaltype wordt er ook voor u afgerond vanwege de vereiste attributen die moeten worden ingesteld zoals hierboven beschreven. Dus uit de schaal, als je
  • In de database (postgresql) wordt het DecimalFieldopgeslagen als een numeric(max_digits, decimal_places)Type, en Storage is ingesteld als “main”, uit het bovenstaande voorbeeld het Type is numeric(4,1)

Meer over DecimalField uit de Django-documenten.

FloatField:

  • Retourneert het ingebouwde float-type, <type 'float'>
  • Geen slimme afronding en kan zelfs resulteren in afrondingsproblemen zoals beschreven in Seths antwoord.
  • Heeft niet de extra formuliervalidatie die u krijgt van DecimalField
  • In de database (postgresql) wordt het FloatFieldopgeslagen als een “dubbele precisie” Type, en Opslag is ingesteld als “plain”

Meer over FloatField uit de Django-documenten.

Van toepassing op beide:

  • Beide velden strekken zich uit van de klasse Fielden kunnen blank, 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_messagesattributen, zoals alle velden die uit Fieldkomen, zouden hebben.
  • De standaard formulierwidget voor beide velden is een TextInput.

Ik kwam deze vraag tegen toen ik op zoek was naar het verschil tussen de twee velden, dus ik denk dat dit mensen in dezelfde situatie zal helpen 🙂

UPDATE: om de vraag te beantwoorden, ik denk dat je met beide kunt wegkomen om valuta weer te geven, hoewel Decimalveel beter past. Er is een afrondingsprobleem wanneer het meetelt voor float’s, dus u moet round(value, 2)gebruiken om uw float-representatie afgerond op twee decimalen te houden. Hier is een snel voorbeeld:

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

Je kunt nog steeds in de problemen komen met floaten round. Zoals hier zien we dat het naar beneden wordt afgerond op een waarde van 5:

>>> round(5.685, 2)
5.68

Maar in dit geval wordt het naar boven afgerond:

>>> round(2.995, 2)
3.0

Het heeft allemaal te maken met hoe de float in het geheugen wordt opgeslagen. Zie hier.


Antwoord 3, autoriteit 8%

Ik weet dat dit super oud is, maar ik kwam het tegen toen ik op zoek was naar iets heel anders, en ik wilde zeggen dat het in het algemeen niet raadzaam is om drijvende-kommagetallen (float ofdecimaal) te gebruiken ) voor valuta, aangezien wiskundige afronding met drijvende komma altijd zal leiden tot kleine rekenfouten die in de loop van de tijd tot zeer grote verschillen kunnen leiden.

Gebruik in plaats daarvan een geheel getal of een tekenreeks naar keuze. Vermenigvuldig uw valuta om de decimale plaats naar het einde te verplaatsen en maak een geheel getal wanneer u het opslaat, en verplaats dat decimaalteken vervolgens terug naar waar het hoort wanneer u het moet tonen. Dit is eigenlijk hoe banken (en de meeste valutabibliotheken) omgaan met het opslaan van gegevens en het zal u later veel problemen besparen.

Ik heb dit op de harde manier geleerd omdat het niet echt een algemeen onderwerp is; misschien voorkomt dit dat iemand anders hetzelfde doet.


Antwoord 4, autoriteit 5%

edit: het Satchmo-project is niet langer actief, dus bekijk deze alternatieven voor het omgaan met valuta


Het op Django gebaseerde Satchmo Projectheeft een CurrencyField en CurrencyWidget die het bekijken waard zijn.

Bekijk de satchmo_utils app-map voor de bron

Other episodes