Django 表单初始化问题 - 如何在超类中设置本地化?



我有一个模型表单,我根据用户的区域设置混合了英制和公制单位(例如 m/s 和 fps(,因此表单是使用手动添加的表单字段和引用模型的混合。

现在,我们以多种形式执行此操作,因此创建了一个超类 LocalizedModel 表单,该表单只需迭代子类字段,如果为十进制,则为所有字段设置 localized= True。

预期的结果是,在模板中生成表单时;所有小数字段都应本地化(或 .(,并使用文本输入而不是数字。

奇怪的是;

  • 当使用遍历字段并设置事物的超类时,表单未本地化,仍使用数字输入。

  • 当直接在字段中设置 localize = True 时,它起作用(文本和小数分隔符设置正确(

Python 3 和 Django 2.0.6 和 USE_L10N 是真的。

知道为什么会这样吗?

请参阅下面的代码片段

# -- example -- 
class RecipeForm(LocalizedModelForm):
cost = forms.DecimalField(label='Cost', initial=0, min_value=0, localize=True)
cost_2 = forms.DecimalField(label='Other Costs', initial=0, min_value=0)
# cost has manually set - works in template
# cost_2 and weight - expected that LocalizedModel for should set them, but no
class Meta:
model = Recipe   
fields = [
'cost',
'cost_2',
'weight', 
]
def __init__(self, *args, **kwargs):
super(RecipeForm, self).__init__(*args, **kwargs)
# ---------------------------------------------------------
class LocalizedModelForm(django.forms.ModelForm):
def __new__(cls, *args, **kwargs):
new_class = super(LocalizedModelForm, cls).__new__(cls)
for field in list(new_class.base_fields.values()):
if isinstance(field, django.forms.DecimalField):
field.localize = True
field.widget.is_localized = True
return new_class

在初始化字段属性后,您正在更改字段属性,这基本上意味着该字段已经呈现NumberInput小部件,因为它在没有localize属性的情况下初始化。

解决方案是使用适当的参数调用字段的__init__方法以重新初始化对象。

或者,查看类IntegerField(DecimalField的超类(__init__方法,可以看到如果localizeTruewidgetNumberInput,那么它将始终将超类Field的小部件设置为TextInput

解决方案

from django.forms.widgets import TextInput
def __new__(cls, *args, **kwargs):
new_class = super(LocalizedModelForm, cls).__new__(cls)
# keep the same reference to the field, change to `items`.
for field_name, field in new_class.base_fields.items():
if isinstance(field, django.forms.DecimalField):
widget = TextInput()
extra_attrs = field.widget_attrs(widget)
if extra_attrs:
widget.attrs.update(extra_attrs)
field.widget = widget
return new_class

最新更新