我正在尝试使用单一货币进行自己的字段计算,我无法在数据库中使用十进制数据类型,这是我到目前为止所拥有的。我真的只是学习自定义字段类型,我不确定我做错了什么。
class MoneyField(models.DecimalField):
"""
"""
__metaclass__ = models.SubfieldBase
def __init__(self, verbose_name=None, name=None, max_digits=10, decimal_places=2, seperator=',', dp='.', pos='', neg='-', trailneg='', **kwargs):
models.DecimalField.__init__(self, verbose_name, name, decimal_places=2, max_digits=10, **kwargs)
def get_internal_type(self):
return models.DecimalField.__name__
def pre_save(self, model_instance, add):
value = getattr(model_instance, self.attname)
if self.decimal_places > 0:
dp_modifier = Decimal(1 / Decimal(pow(10, self.decimal_places)))
else:
dp_modifier = Decimal(1)
if value != None:
value = Decimal(str(value))
print value
print type(value.quantize(Decimal(dp_modifier)))
return value.quantize(Decimal(dp_modifier))
def to_python(self, value):
try:
if self.decimal_places > 0:
dp_modifier = Decimal(1 / Decimal(pow(10, self.decimal_places)))
else:
dp_modifier = Decimal(1)
if value != None:
value = Decimal(str(value))
return super(MoneyField, self).to_python(value).quantize(Decimal(dp_modifier))
except AttributeError:
return None
def get_db_prep_save(self, value, connection):
return float(value)
def get_prep_value(self, value):
return float(value)
例外:
Environment:
Request Method: GET
Request URL: http://127.0.0.1:8001/appdata/joinery/costing/cost-boughtin-by-item/glass/1A346B0F-0705-11E2-9E84-7071BCB8D2AB/
Django Version: 1.3.1
Python Version: 2.6.2
Installed Applications:
['django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'appdata.generic',
'appdata.contacts',
'appdata.dashboard',
'appdata.scheduler',
'appdata.financial',
'appdata.work',
'appdata.boughtin',
'appdata.bespoke',
'appdata.joinery',
'appdata.home',
'appdata.globaltags',
'appdata.importdata',
'appdata.database',
'appdata.ads',
'appdata.workshop',
'appdata.transfer',
'appdata.setup',
'appdata.languages',
'appdata.machine_output',
'appdata.machine_output.modules',
'appdata.printing',
'django_cpserver',
'appdata.djangologdb',
'raven.contrib.django']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'appdata.middleware.UserAgent',
'appdata.middleware.SiteLogin',
'appdata.middleware.RequestIdent',
'appdata.middleware.ProfilerMiddleware',
'django.middleware.transaction.TransactionMiddleware',
'djangologdb.middleware.LoggingMiddleware',
'raven.contrib.django.middleware.Sentry404CatchMiddleware')
Traceback:
File "C:\JoinerySoft\Development\working folder\lib\site-packages\django\core\handlers\base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File "C:\JoinerySoft\Development\working folder\appdata\joinery\costing.py" in cost_boughtin
202. net_cost, charge_out, xml = calc_model.objects.cost_by_item(item,get_xml=True)
File "C:\JoinerySoft\Development\working folder\appdata\joinery\models.py" in cost_by_item
719. return self._cost_component_list(item_list, costbook, get_xml, item=item)
File "C:\JoinerySoft\Development\working folder\appdata\joinery\models.py" in _cost_component_list
699. calc_data = self._cost_components(calc_item_list, costbook)
File "C:\JoinerySoft\Development\working folder\appdata\joinery\models.py" in _cost_components
688. calc_item.apply_cost(cost_item, item_cache)
File "C:\JoinerySoft\Development\working folder\appdata\joinery\models.py" in apply_cost
1024. calc_component.save()
File "C:\JoinerySoft\Development\working folder\lib\site-packages\django\db\models\base.py" in save
460. self.save_base(using=using, force_insert=force_insert, force_update=force_update)
File "C:\JoinerySoft\Development\working folder\lib\site-packages\django\db\models\base.py" in save_base
526. rows = manager.using(using).filter(pk=pk_val)._update(values)
File "C:\JoinerySoft\Development\working folder\lib\site-packages\django\db\models\query.py" in _update
491. return query.get_compiler(self.db).execute_sql(None)
File "C:\JoinerySoft\Development\working folder\lib\site-packages\django\db\models\sql\compiler.py" in execute_sql
869. cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)
File "C:\JoinerySoft\Development\working folder\lib\site-packages\django\db\models\sql\compiler.py" in execute_sql
725. sql, params = self.as_sql()
File "C:\JoinerySoft\Development\working folder\lib\site-packages\django\db\models\sql\compiler.py" in as_sql
834. val = field.get_db_prep_save(val, connection=self.connection)
File "C:\JoinerySoft\Development\working folder\lib\site-packages\django\db\models\fields\subclassing.py" in inner
28. return func(*args, **kwargs)
File "C:\JoinerySoft\Development\working folder\lib\site-packages\django\db\models\fields\__init__.py" in get_db_prep_save
786. return connection.ops.value_to_db_decimal(self.to_python(value),
File "C:\JoinerySoft\Development\working folder\lib\site-packages\django\db\models\fields\__init__.py" in to_python
761. return decimal.Decimal(value)
File "C:\JoinerySoft\Development\working folder\lib\decimal.py" in __new__
653. "First convert the float to a string")
Exception Type: TypeError at /appdata/joinery/costing/cost-boughtin-by-item/glass/1A346B0F-0705-11E2-9E84-7071BCB8D2AB/
Exception Value: Cannot convert float to Decimal. First convert the float to a string
答案 0 :(得分:1)
我认为你可能会从错误的方向接近问题。您应该尝试从float字段中获取Decimal值,而不是尝试将db中的Decimal字段保存为float。
尝试这种性质的东西:
class MoneyField(models.FloatField):
__metaclass__ = models.SubfieldBase
def to_python(self, value):
t_value = type(value)
if t_value is Decimal:
return value
elif t_value is float:
return Decimal.from_float(value)
elif t_value in (str, unicode,):
return Decimal(value)
else:
raise TypeError('Unsupported value type: %s' % str(t_value))
def get_prep_value(self, value):
return float(value)
所以它的作用是它与float字段相同,因此与db中的float字段兼容。但是,每当检索到值时,它都会确保返回浮点数的十进制版本。在尝试保存字段时,它会将其转换为浮动状态。
没有测试过,所以不确定100%是否正确,但我认为这应该让你朝着正确的方向前进。除此之外,你可以强制执行所有的金钱......