在任何类型的Django Field上,都可以使用validators,我可以勾挂自己的自定义验证器.我知道我无法更改验证器中的值,它必须返回Nonedjango.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类型然后编写自定义Field.to_python(),我是否可以像使用验证器一样实现同样的功能?

我仍在学习,而且还没有达到Form的水平,但当通过Djano命令从CSV进行种子 seeder 时,我正在try 实现上述目标.是的,我可以在从CSV读取时立即修改该值,但我正在try 找出是否有一个地方可以这样做,这样我就不必为表单单独编写它.

推荐答案

这被称为cleaning,Django不允许在Model本身中勾入"清洁工",或者至少不容易.您可以在Form上使用clean_fieldname()、序列化器中使用validate_fieldname()等处理输入的级别进行清理.

您可以重写.save() method [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()

Django相关问答推荐

Django-表单(ModelForm)中的数据不保存在现有数据库中

Django通用列表视图与多查询搜索

身份验证有效,但登录无效.一直卡在pending

QuerySet对象在bulk_update中没有属性pk

Django中的 联合(Union) 和相交(Intersect)

使用 args 和选项编写自定义管理命令 - 所需字段说明

关于Django中批量保存对象的问题

Django 表单有 Select 但也有自由文本选项?

获取 Django 中的缓存键列表

手动触发 Django 邮件错误报告

在 Django 中获取下一个和上一个对象

CSS 文件中的 Django 媒体 URL

在 Django 中注册用户的最佳方法

django:TypeError:'tuple'对象不可调用

Django表单集:首先需要?

在 django admin 中链接到外键对象

Django 模型:delete() 未触发

Jinja2中的多级模板继承?

Django 测试客户端方法覆盖标头

Django REST 框架中的每个字段权限