Django创建自定义模型字段 [英] Django creating a custom model field
问题描述
我正在尝试在Django中创建一个自定义字段,该字段将使用十进制货币值(例如:1.56英镑)并将其保存为数据库中的整数(例如:156)来存储货币值。
I am trying to create a custom field in Django which will take a decimal currency value (example: £1.56) and save it in the database as an Integer (example: 156) to store currency values.
这是我到目前为止的结果(我已经测试了固定值)
This is what I have so far (I have put fixed values to test)
class CurrencyField(models.DecimalField):
__metaclass__ = models.SubfieldBase
def get_internal_type(self):
return 'PositiveIntegerField'
def to_python(self, value):
print "CurrentField to_python"
return Decimal(value)/100
def get_db_prep_value(self, value, connection, prepared=False):
print "CurrentField get_db_prep_value"
if value is None:
return value
print type(value)
return int(value*100)
我正在关注用于创建自定义模型字段的Python 1.7文档。
在上面的代码中,当我使用此字段保存模型时,永远不会调用 get_db_prep_value
方法。 to_python
方法可以正常工作(如果我在数据库中手动输入值,它将返回正确的十进制数),但是它将永远不会保存正确的值。
In the above code, the get_db_prep_value
method is never being called when I save the model using this field. The to_python
method is working fine (if I manually enter the value in the DB it will return the correct decimal), however it will never save the correct value.
我也尝试过使用 get_prep_value
,并且结果相同。
I have also tried using get_prep_value
and this has the same result.
如何使它保存正确的值?
How can I make it save the correct value?
推荐答案
我已经使用了Django这段代码了一段时间,但后来意识到在保存数据库之前转换为整数时会引入浮点伪像。
I've been using this Django snippet for some time, but realized later it was introducing floating-point artifacts when converting to an integer before saving the the database.
此外,自Django 1.9起, SubfieldBase已弃用,我们应该改用Field.from_db_value。因此,我已经编辑了代码来解决这两个问题。
Also, as of Django 1.9 SubfieldBase has been deprecated and we should use Field.from_db_value instead. So I've edited the code to fix both of these issues.
class CurrencyField(models.IntegerField):
description = "A field to save dollars as pennies (int) in db, but act like a float"
def get_db_prep_value(self, value, *args, **kwargs):
if value is None:
return None
return int(round(value * 100))
def to_python(self, value):
if value is None or isinstance(value, float):
return value
try:
return float(value) / 100
except (TypeError, ValueError):
raise ValidationError("This value must be an integer or a string represents an integer.")
def from_db_value(self, value, expression, connection, context):
return self.to_python(value)
def formfield(self, **kwargs):
from django.forms import FloatField
defaults = {'form_class': FloatField}
defaults.update(kwargs)
return super(CurrencyField, self).formfield(**defaults)
这篇关于Django创建自定义模型字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!