首页 > 解决方案 > 在 Django 管理界面中使用不同的小数分隔符进行前端验证

问题描述

我查看了 stackoverflow 上的每一个类似问题,并尝试了几乎所有方法。这似乎很容易做到:我只想在 Django 管理界面中允许,作为小数点分隔符。FloatField目前,这取决于本地化,但我总是想允许它。如果它只是一个,对我来说甚至可以TextInput,但我需要,工作。settings.py 中的设置DECIMAL_SEPARATOR不起作用。

我的问题类似于这个 6 岁的未回答的问题:如何只在 django 中覆盖 DECIMAL_SEPARATOR,同时保持本地化不变?

我设法将TextInput小部件用于 FloatFields,如下所示:

class ExampleAdminForm(forms.ModelForm):
    class Meta:
        model = Example

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for key, value in self.fields.items():
            if isinstance(value, FloatField):
                self.fields[key].widget = TextInput()  

小部件可以工作,但输入 like1,23会导致错误消息Enter a number。我必须实现我自己的自定义 FloatField 来覆盖清理to_python以允许不同的小数分隔符,但是我仍然需要一个不同的小部件。这似乎非常复杂,有没有更好的方法?如果没有,我如何更改小部件中的前端验证以忽略本地化并使用我自己的正则表达式模式?

标签: pythondjango

解决方案


修补该to_python方法,或使用覆盖该方法的自定义表单字段类。

单线答案:

self.fields[key].to_python = lambda v: self.fields[key].__class__.to_python(self.fields[key], '.'.join(v.rsplit(',', 1)) if len(v.rsplit(',', 1)[-1]) < 3 else v)

作为包装函数:

self.fields[key].to_python = allow_comma_decimal_separator(self.fields[key].to_python)
def allow_comma_decimal_separator(old_to_python):
    def to_python(value):
        if ',' in value:
            lvalue, decimals = value.rsplit(',', 1)
            if len(decimals) < 3:
                value = '.'.join((lvalue, decimals))
        return old_to_python(value)
    return to_python

即如果一个逗号在值中,并且最右边的逗号后面的子字符串的长度小于 3(所以我们假设它不是千位分隔符),那么我们通过在前后连接子字符串来替换逗号一段时间。

对于使用可重用表单字段类的显式字段

这将被认为不那么“hacky”。

class AllowCommaDecimalSeparatorFloatField(forms.FloatField):

    def to_python(self, value):
        if ',' in value:
            lvalue, decimals = value.rsplit(',', 1)
            if len(decimals) < 3:
                value = '.'.join((lvalue, decimals))
        return super().to_python(value)

在您的表单Meta类中:

field_classes = {
    'myfield': AllowCommaDecimalSeparatorFloatField,
}

对于所有 FloatFields

要影响所有FloatField实例(尚未实例化),请将其放在模块的顶部:

old_to_python = forms.FloatField.to_python


def to_python(self, value):
    if ',' in value:
        lvalue, decimals = value.rsplit(',', 1)
        if len(decimals) < 3:
            value = '.'.join((lvalue, decimals))
    return old_to_python(self, value)


forms.FloatField.to_python = to_python

推荐阅读