如何在列表模板中用货币符号和纯十进制表示Django货币字段进行编辑



当我在列表模板或详细信息(只读)模板中显示货币时,我希望能够显示包含货币符号的字段值的漂亮版本:"$1000.00">

但是,在编辑记录时,我希望在不带任何货币符号的TextInput框中显示"100.00"。

我做了一个定制的模型。DecimalField类和形式。DecimalField类来表示Django应用程序中的货币。

因此,我正试图想出一种方法,在模板中为字段值提供一个漂亮的替代版本(即,格式正确,便于查看,但不适合编辑)。我知道有一些模板过滤器可以让你实现这一点,但我相信这会阻止我遍历表单中的字段并显示它们的值。

如果我能给我的自定义字段类添加一个漂亮的属性,我就可以检查它是否存在于模板中并显示它

class MoneyFormField(forms.DecimalField):
def __init__(self, *args, **kwargs):
# I plan to add symbol localization code here
self.symbol= '$'
def prepare_value(self, value):
# assign pretty value to an attribute that template can access
self.pretty = self.pretty_value(value)            
try:
return round(Decimal(value),2)
except:
return 0
def pretty_value(self, value):
if not value:
value = 0
return self.symbol + str(round(Decimal(value),2))

问题是,为了访问模板中的漂亮值,我必须首先访问原始值,以便调用prepare_value()。

如果我尝试在这样的模板中打印漂亮的值。。。

{% for field in payment_form %}
{{ field.field.pretty }} {{ field.value }} {{ field.field.pretty }} 
{% endfor %}

然后第一个漂亮的被忽略,但最后一个漂亮的打印。

如果我能做到这一点,那么我会在这样的模板中显示一个漂亮的值(或者默认值,如果漂亮不存在的话):

{% if field.field.pretty %}
{{ field.field.pretty}}
{% else %}
{{ field.value }}
{% endif %}

是否有人对为模板提供字段的替代表示有任何建议?

TL;DR-如何访问表单字段的init中的字段值?

我想出了一个解决方案,但由于我是Django和python的新手,我可能会让事情变得不必要地过于复杂。所以我很乐意听到任何反馈!

总之:我希望我的货币字段有一个"漂亮"的版本,可以在某些模板(如列表和只读详细信息)中将货币显示为"100.00美元",而不是"100.00"。

我创建了一个货币模型字段,用于指定我的自定义表单字段MoneyFormField:

class MoneyField(models.DecimalField):
def __init__(self, *args, **kwargs):
kwargs['max_digits'] = 13
kwargs['decimal_places'] = 4
kwargs['default'] = 0
def formfield(self, **kwargs):
defaults = {'form_class': MoneyFormField}
defaults.update(kwargs)
return super(MoneyField, self).formfield(**defaults)        

这是我的MoneyFormField表单字段。注意对"get_bound_field"的调用:

class MoneyFormField(forms.DecimalField):
def __init__(self, *args, **kwargs):
self.widget = MoneyTextInput() # custom widget I'm experimenting with
self.prefix = '$'            
super(MoneyFormField, self).__init__(*args, **kwargs)
def get_bound_field(self, form, field_name):
return MoneyBoundField(form, self, field_name)        
def prepare_value(self, value):
try:
return round(Decimal(value),2)
except:
return 0

MoneyBoundField使该字段的"漂亮"版本可用于模板:

class MoneyBoundField(BoundField):
def pretty(self):
return self.field.prefix+str(self.value())

如果我只是这样做,那么我可以通过首先检查是否存在漂亮的值来打印漂亮的值,如果不存在,则打印原始值,如下所示:

{% for somefield in payment_form %}
{% if somefield.pretty %}
{{ somefield.pretty }}
{% else %}
{{ somefield.value }}
{% endif %}    
{% endfor %}

但我宁愿做这样的事情:

{% for somefield in payment_form %}
{{ somefield.pretty }}
{% endfor %}

因此,我不得不在boundfields.py中的Django BoundField主类中添加两行:

boundfield.py
class BoundField(object):
...
def pretty(self):
# return default value.  Let descendant classes override this function where desired
return self.value()

这是我采用的另一种方法。我现在只是使用一个模板过滤器来使字段变得漂亮,而不是在BoundField.py中扰乱django BoundField的主要类定义。过滤器执行以下操作:

  • 如果字段是选择字段,它会将选择索引值转换为描述字符串
  • 如果该字段有一个自定义的formfield,带有一个自定义BoundField,并且有一个名为"漂亮"的函数,它会调用该函数并返回值
  • (已注释完毕)如果适用,您可以尝试调用自定义表单字段类中的特定方法。这样就不需要在formfield类中定义BoundField
  • 如果这些不适用,则只返回未修改的字段值

这是我的app_filters.py:中的代码

from django.forms.fields import ChoiceField
@register.filter
def pretty_filter(field):
# is this a better way to get the field's value?
# field_value = field.form.initial[field.name]
# get the field's value (for choice fields, this is the integer index used to look up the verbose string in the choices dict)
field_value = field.value()
if field_value is None:
return ''
# the the field has 'choices' then return the verbose string for the choice
if isinstance(field.field, ChoiceField): 
for (choices_index, description) in field.field.choices: 
if choices_index == field_value: 
return description
return '' # no match found
# # if your model.field's formfield has a function called
# # another_custom_function() you can call it this way:
# try:
#     return field.field.another_custom_function()
# except:
#     pass
# attempt to return pretty value if field has th
try:
return field.pretty()
except:
# else return default value
return field_value

我还更改了我的自定义货币字段的漂亮函数,所以它添加了一个逗号(可以更改以处理本地化):

class MoneyBoundField(BoundField):    
def pretty(self):
# return $12,345.67
return "{}{:,.2f}".format(self.field.prefix,self.value())
class MoneyFormField(forms.DecimalField):
def __init__(self, *args, **kwargs):
self.widget = MoneyTextInput()
self.prefix = '$'
super(MoneyFormField, self).__init__(*args, **kwargs)
def get_bound_field(self, form, field_name):
return MoneyBoundField(form, self, field_name)    

然后在我的模板中,我这样使用它:

{% load app_filters %}
{% for item in payment_form %}
{{item|pretty_filter}}
{% endfor %}                   

大部分过滤代码都是从用户Simple10复制过来的:https://code.djangoproject.com/ticket/10427#comment:18

请分享您的想法或评论!

最新更新