Django: как я должен хранить денежное значение?
Я столкнулся с проблемой парадигмы здесь. Я не знаю, должен ли я хранить деньги как Decimal (), или я должен хранить их как строку и преобразовывать ее в decimal. Мои рассуждения таковы:--1-->
PayPal требует 2 десятичных знаков, поэтому, если у меня есть продукт, который равен 49 долларам, PayPal хочет увидеть 49.00. DecimalField () Django не устанавливает десятичную сумму. Он хранит только максимальное количество десятичных знаков. Итак, если у вас есть 49 в там, и у вас есть поле, установленное на 2 десятичных знака, оно все равно будет хранить его как 49. Я знаю, что Django-это в основном литье типа, когда он десериализуется из базы данных в десятичное число (поскольку базы данных не имеют десятичных полей), поэтому меня не полностью волнуют проблемы скорости, так как я занимаюсь проблемами дизайна этой проблемы. Я хочу сделать то, что лучше для расширяемости.
или, еще лучше, кто-нибудь знает, как настроить Django DecimalField (), чтобы всегда форматировать с стиль форматирования TWO_PLACES.
8 ответов
вы можете использовать .quantize()
метод. Это округлит десятичное значение до определенного количества мест, аргумент, который вы предоставляете, указывает количество мест:
>>> from decimal import Decimal
>>> Decimal("12.234").quantize(Decimal("0.00"))
Decimal("12.23")
также может потребоваться аргумент, чтобы указать, какой подход округления вы хотите (различные системы учета могут хотеть другого округления). Дополнительная информация в Python docs.
ниже пользовательское поле, которое автоматически создает правильное значение. Обратите внимание, что это только тогда, когда извлекается из базы данных и не поможет вам, когда вы установите его самостоятельно (пока вы не сохраните его в БД и не получите его снова!).
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
[edit]
добавил __metaclass__
см. Django: почему это настраиваемое поле модели ведет себя не так, как ожидалось?
Я думаю, вы должны сохранить его в десятичном формате и форматировать его в формате 00.00 только затем отправьте его в PayPal, например:
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'])
деньги должны храниться в денежном поле, которого, к сожалению, не существует. Поскольку деньги-это двумерное значение (сумма, валюта).
здесь python-деньги lib, у этого много вилок, но я не нашел ни одной рабочей.
рекомендации:
python-деньги вероятно, лучшая вилка https://bitbucket.org/acoobe/python-money
Джанго-деньги рекомендовано akumria: http://pypi.python.org/pypi/django-money/ (еще не пробовал).
Я предлагаю избегать смешивания представления с хранением. Сохраните данные в виде десятичного значения с 2 местами.
в слое пользовательского интерфейса отобразите его в форме, подходящей для пользователя (поэтому, возможно, опустите ".00").
когда вы отправляете данные в PayPal, форматируйте его так, как требует интерфейс.
основываясь на ответе @Will_Hardy, здесь вам не нужно каждый раз указывать max_digits и decimal_places:
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
по моему опыту, а также из другие, деньги лучше всего хранить в виде комбинации валюты и суммы в центах.
очень легко отрегулировать и высчитать с ним.
вы храните его как десятичное поле и вручную добавляете десятичные знаки, Если вам нужно, как сказала Валя, используя основные методы форматирования.
вы даже можете добавить метод модели к вам продукт или модель транзакции, которая будет выплевывать десятичное поле как соответствующим образом отформатированную строку.