Используйте различные десятичные разделители для валидации на фронтенде в интерфейсе 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