Используйте различные десятичные разделители для валидации на фронтенде в интерфейсе Django Admin
Я просмотрел все похожие вопросы на stackoverflow и перепробовал почти все.
Кажется, это легко сделать: Я просто хочу разрешить ,
в качестве десятичного разделителя для FloatField
в интерфейсе администратора Django. На данный момент это зависит от локализации, но я всегда хочу разрешить это. Для меня было бы даже нормально, если бы это было просто TextInput
, но для работы мне нужно ,
. Установка DECIMAL_SEPARATOR
в settings.py не работает.
Мой вопрос похож на этот 6-летний вопрос без ответа: Как переопределить только DECIMAL_SEPARATOR в django, сохранив при этом локализацию?
Мне удалось использовать виджет 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()
Виджет работает, но ввод типа 1,23
приводит к сообщению об ошибке Enter a number
. Я не могу найти, где происходит валидация, поскольку validate()
из FloatField никогда не срабатывает.
Есть ли способ, например, переопределить FloatField или виджет TextInput, чтобы разрешить использование других десятичных разделителей? Или какой-либо другой способ?
Исправьте метод 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 (поэтому мы предполагаем, что это не разделитель тысяч), то мы заменяем запятую точкой, соединяя подстроку до и после точкой.
Для явных полей, использующих многоразовый класс поля формы
Это будет считаться менее "халтурным".
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