Есть ли в Django хук для изменения значения поля?
На любом типе Django Field, доступен validators
, где я могу подключить свой собственный валидатор. Как я понимаю, я не могу изменить значение в валидаторе, он должен возвращать либо None
, либо django.core.exceptions.ValidationError
.
Я хочу изменить значение самого поля, прежде чем оно будет сохранено. Например, я хочу сохранить числовой код ISO 3166 в виде столбца:
def digit_only(value):
if not value.isdigit():
raise ValidationError(
_("%(value)s contains a non-digit"),
params={"value": value},
)
class Country(models.Model):
# ...
iso3166_numeric = models.CharField(max_length=3, validators=[digit_only])
# ...
Пока все хорошо. Теперь, если вводимое значение равно '1', я хочу преобразовать его в '001' перед тем, как значение будет сохранено в таблице. Могу ли я добиться этого без создания нового типа поля и написания пользовательского Field.to_python()
, так же просто, как и с помощью валидаторов?
Я все еще учусь, и я еще не дошел до Forms, но я пытаюсь достичь вышеупомянутого при посеве из CSV через команду Djano. Да, я могу изменить значение сразу при чтении из CSV, но я пытаюсь выяснить, есть ли одно единственное место, где я могу это сделать, чтобы мне не пришлось писать это отдельно и для Forms.
Это называется очисткой, и Django не позволяет подключать "очистители" в самом Model
, или, по крайней мере, не так просто. Вы можете чистить на уровне обработки ввода с помощью clean_fieldname()
на Form
s, validate_fieldname()
в сериализаторе и т.д.
Вы могли бы переопределить метод .save()
[Django-doc], но они не работают, например, для массового создания.
Поэтому я бы посоветовал просто сделать это с помощью пользовательского поля, например:
from django.core.validators import RegexValidator
class Iso3166NumericField(models.CharField):
def __init__(self, *args, **kwargs):
kwargs.setdefault('max_length', 3)
validators = kwargs.setdefault('validators', [])
validators.append(RegexValidator('^\\d{,3}$'))
return super().__init__(*args, **kwargs)
def to_python(self, value):
if value is not None:
value = value.zfill(3)
return super().to_python(value)
class Country(models.Model):
# …
iso3166_numeric = Iso3166NumericField()