program tip

Django : 화폐 가치를 어떻게 저장해야합니까?

radiobox 2020. 11. 24. 07:51
반응형

Django : 화폐 가치를 어떻게 저장해야합니까?


나는 여기서 패러다임 문제에 직면하고 있습니다. 돈을 Decimal ()로 저장해야하는지, 아니면 문자열로 저장하고 직접 10 진수로 변환해야하는지 모르겠습니다. 내 추론은 다음과 같습니다.

PayPal은 소수점 이하 2 자리가 필요 하므로 49 달러 인 제품이있는 경우 PayPal은 49.00이 전송되는 것을보고 싶어합니다. Django의 DecimalField ()는 십진수를 설정하지 않습니다. 최대 소수점 이하 자릿수 만 저장합니다. 따라서 거기에 49가 있고 필드가 소수점 이하 2 자리로 설정되어 있으면 여전히 49로 저장할 것입니다. Django는 기본적으로 데이터베이스에서 Decimal로 역 직렬화 할 때 유형 캐스팅이라는 것을 알고 있습니다. 소수 필드가 없음),이 문제의 디자인 문제만큼 속도 문제에 완전히 관심이 없습니다. 확장 성을 위해 최선을 다하고 싶습니다.

또는 더 나은 방법은 django DecimalField ()를 항상 TWO_PLACES 형식화 스타일로 형식화하도록 구성하는 방법을 아는 사람이 있습니까?


.quantize()방법 을 사용할 수 있습니다 . 이것은 10 진수 값을 특정 자릿수로 반올림하며, 제공하는 인수는 자릿수를 지정합니다.

>>> from decimal import Decimal
>>> Decimal("12.234").quantize(Decimal("0.00"))
Decimal("12.23")

또한 원하는 반올림 접근 방식을 지정하는 인수를 사용할 수 있습니다 (다른 회계 시스템은 다른 반올림을 원할 수 있음). Python 문서 에 더 많은 정보가 있습니다.

다음은 올바른 값을 자동으로 생성하는 사용자 정의 필드입니다. 이것은 데이터베이스에서 검색된 경우에만 해당되며 사용자가 직접 설정하면 도움이되지 않습니다 (db에 저장하고 다시 검색 할 때까지).

from django.db import models
from decimal import Decimal
class CurrencyField(models.DecimalField):
    __metaclass__ = models.SubfieldBase

    def to_python(self, value):
        try:
           return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01"))
        except AttributeError:
           return None

[편집하다]

추가됨 __metaclass__, Django :이 사용자 정의 모델 필드가 예상대로 작동하지 않는 이유는 무엇입니까?


난 당신이 진수 형식으로 저장하고 00.00 형식으로 포맷해야한다고 생각 에만 이 같은 페이팔로 전송 한 후 :

pricestr = "%01.2f" % price

원하는 경우 모델에 메소드를 추가 할 수 있습니다.

def formattedprice(self):
    return "%01.2f" % self.price

남부 마이그레이션을 추가하는 파티 버전에 늦었습니다.

from decimal import Decimal
from django.db import models

try:
    from south.modelsinspector import add_introspection_rules
except ImportError:
    SOUTH = False
else:
    SOUTH = True

class CurrencyField(models.DecimalField):
    __metaclass__ = models.SubfieldBase

    def __init__(self, verbose_name=None, name=None, **kwargs):
        decimal_places = kwargs.pop('decimal_places', 2)
        max_digits = kwargs.pop('max_digits', 10)

        super(CurrencyField, self). __init__(
            verbose_name=verbose_name, name=name, max_digits=max_digits,
            decimal_places=decimal_places, **kwargs)

    def to_python(self, value):
        try:
            return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01"))
        except AttributeError:
            return None

if SOUTH:
    add_introspection_rules([
        (
            [CurrencyField],
            [],
            {
                "decimal_places": ["decimal_places", { "default": "2" }],
                "max_digits": ["max_digits", { "default": "10" }],
            },
        ),
    ], ['^application\.fields\.CurrencyField'])

돈은 슬프게도 존재하지 않는 돈 필드에 저장되어야합니다. 돈은 2 차원 적 가치 (금액, 통화)이기 때문입니다.

파이썬 - 돈 많은 포크를 가지고 lib 디렉토리, 아직 나는 작업 하나를 발견하지 않았습니다.


권장 사항 :

python-money 아마도 최고의 포크 https://bitbucket.org/acoobe/python-money

akumria가 추천하는 django-money : http://pypi.python.org/pypi/django-money/ (아직 시도해 본 적이있는).


I suggest to avoid mixing representation with storage. Store the data as a decimal value with 2 places.

In the UI layer, display it in a form which is suitable for the user (so maybe omit the ".00").

When you send the data to PayPal, format it as the interface requires.


Building on @Will_Hardy's answer, here it is so you don't have to specify max_digits and decimal_places every time:

from django.db import models
from decimal import Decimal


class CurrencyField(models.DecimalField):
  __metaclass__ = models.SubfieldBase

  def __init__(self, verbose_name=None, name=None, **kwargs):
    super(CurrencyField, self). __init__(
        verbose_name=verbose_name, name=name, max_digits=10,
        decimal_places=2, **kwargs)

  def to_python(self, value):
    try:
      return super(CurrencyField, self).to_python(value).quantize(Decimal("0.01"))
    except AttributeError:
      return None

In my experience and also from others, money is best stored as combination of currency and the amount in cents.

It's very easy to handle and calculate with it.


You store it as a DecimalField and manually add the decimals if you need to, as Valya said, using basic formatting techniques.

You can even add a Model Method to you product or transaction model that will spit out the DecimalField as an appropriately formatted string.

참고URL : https://stackoverflow.com/questions/2013835/django-how-should-i-store-a-money-value

반응형