在GAE + WTForms中处理价格数值
我在使用谷歌应用引擎(Python)和Jinja2,想要利用webapp2的功能来处理货币的国际化和本地化,也就是把价格存储为数字,并通过webapp2内置的i18n方法进行正确的格式化。因此,我首先需要确保我的价格数据类型是正确的。
我正在从一个原型迁移过来,之前是用字符串来表示价格,现在想用更实际的实现方式,使用某种数字数据类型来表示价格,同时再加一个变量来表示货币类型。所以在迁移的过程中,我会同时使用这两个变量,逐步将价格从字符串转换为数字,去掉字符串数据类型,并进行一个mapreduce任务来更新旧的数据实体,把价格从文本/字符串转换为基于数字的变量,比如整数或小数。
我的环境(谷歌应用引擎)不支持小数数据类型,我也可以只使用整数,因为我的使用场景是买卖比较贵的物品,比如房子、车子等,这些情况下美元是重要的,而分通常只显示为00。所以我放弃了实现小数属性的项目,反正也有点麻烦,现在我想知道设置价格的正确方式是什么,是否在保存之前必须进行类型转换?
也就是说,这样做是否正确:
form = EntityForm(self.request.params)
if form.validate():
entity.title = form.title.data
entity.name = form.name.data
entity.email = form.email.data
entity.text = form.text.data
entity.set_password(form.password.data)
entity.price = form.price.data
try:
if form.price.data:
form.price.data=form.price.data.replace(',','.').replace(' ', '')
entity.integer_price = int(form.price.data)
except:
pass
或者我不需要将变量转换为整数,类型转换会在后台自动处理?我认为表单变量是字符串,而价格必须是数字才能正确排序和过滤。
当我使用自定义的小数属性时,开始出现了这个错误:
Traceback (most recent call last):
File "/base/python27_runtime/python27_lib/versions/third_party/webapp2-2.3/webapp2.py", line 545, in dispatch
return method(*args, **kwargs)
File "/base/data/home/apps/s~montaoproject/validation.355292363398040911/i18n.py", line 653, in get
ads = paginator.page(page)
File "/base/data/home/apps/s~montaoproject/validation.355292363398040911/paginator.py", line 42, in page
return Page(self.object_list[bottom:top], number, self)
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 2189, in __getitem__
return self.fetch(limit, start)
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 2084, in fetch
return list(self.run(limit=limit, offset=offset, **kwargs))
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 2237, in next
return self.__model_class.from_entity(self.__iterator.next())
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/search/__init__.py", line 463, in from_entity
return super(SearchableModel, cls).from_entity(entity)
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 1411, in from_entity
entity_values = cls._load_entity_values(entity)
File "/base/python27_runtime/python27_lib/versions/1/google/appengine/ext/db/__init__.py", line 1387, in _load_entity_values
value = prop.make_value_from_datastore(entity[prop.name])
File "/base/data/home/apps/s~montaoproject/validation.355292363398040911/main.py", line 98, in make_value_from_datastore
return decimal.Decimal(value)
File "/base/python27_runtime/python27_dist/lib/python2.7/decimal.py", line 548, in __new__
"Invalid literal for Decimal: %r" % value)
File "/base/python27_runtime/python27_dist/lib/python2.7/decimal.py", line 3844, in _raise_error
raise error(explanation)
InvalidOperation: Invalid literal for Decimal: u''
我使用的代码是:
class DecimalProperty(db.Property):
data_type = decimal.Decimal
def get_value_for_datastore(self, model_instance):
return str(super(DecimalProperty, self).get_value_for_datastore(model_instance))
def make_value_from_datastore(self, value):
return decimal.Decimal(value)
def validate(self, value):
value = super(DecimalProperty, self).validate(value)
if value is None or isinstance(value, decimal.Decimal):
return value
elif isinstance(value, basestring):
return decimal.Decimal(value)
raise db.BadValueError("Property %s must be a Decimal or string." % self.name)
但这对我来说不管用,我开始得到“None”这个字符串,表示没有价格的物品,这导致我的应用无法正常加载,所以我完全放弃了小数的尝试,转而使用整数属性,并验证输入要么为空,要么是整数,这可以通过wtforms来实现。
所以我不再使用自定义的小数属性,我们决定使用整数属性,最坏的情况是如果需要处理货币的分数,我可以使用另一个变量“cents”,这样我就可以用整数表示美元和分,而后者很少或几乎不用。
所以我现在计划的解决方案很简单:
class Article(GeoModel, search.SearchableModel):
integer_price = IntegerProperty() #store dollars as dollars
currency = db.StringProperty(choices=(
'EUR',
'ARS',
'AUD',
'BRL',
'GBP',
'CAD',
'CZK',
'DKK',
'HKD',
'HUF',
'ILS',
'INR',
'JPY',
'MXN',
'NZD',
'NOK',
'PLN',
'PHP',
'SGD',
'SEK',
'SGD',
'CHF',
'USD',
'THB',
'TWB',
), verbose_name='Currency')
price = db.StringProperty(verbose_name='price') #quit using this and use a number instead
你知道我是否真的需要进行类型转换,或者还有其他可能会遇到的陷阱吗?你同意我在这种情况下不需要小数吗(比如广告一辆车、广告一栋房子),尽管在更复杂的定价情况下,我可能需要禁止某些情况,比如“每加仑20美元”这种价格我无法处理,但可以在文本中说明,因为这是特殊的定价(按单位体积),同样如果价格是以分为单位存储。将价格存储为整数属性将允许更好的价格格式化,尤其是因为我的应用是国际化和本地化的。
感谢任何回答或评论。