关于后端:Django笔记四十二之model使用validator验证器

38次阅读

共计 6191 个字符,预计需要花费 16 分钟才能阅读完成。

本文首发于公众号:Hunter 后端

原文链接:Django 笔记四十二之 model 应用 validator 验证器

这一篇笔记介绍一下 model 里的 validator 验证器。

首先,这是个什么货色呢?

在 model 的第四篇笔记里,咱们介绍了字段的一些属性,比方是否容许为空,varchar 类型的字段的最大长度等。

个别在存储前,咱们要手动对数据进行一些校验,比方判断前端传入的字段是否为空,传入的字符最大长度是否超过咱们规定的长度等。

而 validator 验证器就给咱们提供了一个简便的形式能够在存储数据前主动进行校验。

以下是本篇笔记目录:

  1. 自定义验证器
  2. 援用验证器
  3. 校验函数
  4. 测试校验函数
  5. 系统验证器介绍

1、自定义验证器

咱们上面会在 model 中调用一个验证器,它的作用是只容许保留偶数,如果是奇数则会引发 ValidationError。

示例如下:

from django.core.exceptions import ValidationError

def validate_even(value):
    if value % 2 != 0:
        raise ValidationError(f"{value} is not an even number")

如上所示,一个简略的验证器就实现了,它是一个函数,咱们能够手动调用,传入奇数或者偶数尝试,传入偶数不会产生什么,然而传入奇数则会引发一个 ValidationError 的报错。

2、援用验证器

定义好一个验证器之后,咱们在 model 中引入。

咱们这里新建一个 model,名为 TestValidate:

class TestValidate(models.Model):
    even_field = models.IntegerField(default=0, validators=[validate_even])

如上,一个验证器的引入就实现了,当咱们在尝试对数据进行保留的时候,比方创立一条数据:

TestValidate.objects.create(even_field=1)

传入的数据值为 1,是不非法的,然而却能够保留,为什么呢?

这里介绍一下触发验证器的机制。

尽管咱们在 model 里引入了验证器,然而 Django 零碎并不会主动触发,而须要咱们进行手动去触发校验操作。

咱们在下一节介绍一下进行校验的四个函数:

  1. clean_fields()
  2. clean()
  3. validate_unique()
  4. full_clean()

3、校验函数

后面介绍到须要在保留前手动调用校验函数,先介绍一下四个校验函数

1.clean_fields(exclude=None)

接管 exclude 参数,参数类型为列表,列表元素为字段名称,示意传入的字段不进行校验,如果不传该参数,则默认对 model 的所有字段进行校验。

这个函数的操作是,校验 model 里中所有不非法的字段数据,比方没有设置容许为空,但字段的值为空,以及包含设置了 validators 参数的字段。

比方后面咱们设置了 even_field 字段只容许保留偶数,那么在 save() 操作前,调用 clean_fields() 函数,则会引发 validate_even 的报错。

2.clean()

默认是一个空函数,用于咱们继承重写一些校验操作,咱们能够自定义一些 model 的限度需要,比方,它能够进行不同字段间的关联校验

3.validate_unique(exclude=None)

验证的是字段数据是否违反唯一性束缚,其实也就是获取 model 里所有蕴含唯一性束缚的字段,而后去数据库里查问是否蕴含同样的数据,如果存在,则引发验证报错。

唯一性束缚蕴含 unique,unique_for_date,unique_for_year,unique_for_month 等,接管 exclude 参数,和 clean_fields() 函数统一,exclude 为不进行校验的字段

4.full_clean(exclude=None, validate_unique=True)

所以咱们在进行 model 的 save() 操作前,能够依据咱们的须要进行相应的校验操作

也能够间接调用 full_clean() 函数,这个函数会顺次调用 clean_fields,clean,和 validate_unique 函数。

full_clean() 接管两个参数,一个 exclude,接管不校验的字段列表,一个 validate_unique,为布尔型数据,示意是否须要进行唯一性校验

4、测试校验函数

上面咱们挨个对校验函数进行解决测试操作。

首先从新设置一下 model:

# blog/models.py

from django.core.exceptions import ValidationError
from django.db import models


def validate_even(value):
    if value % 2 != 0:
        raise ValidationError(f"{value} is not an even number")


class TestValidate(models.Model):
    even_field = models.IntegerField(default=0, validators=[validate_even])
    name = models.CharField(unique=True, max_length=20, default=None)

1. 测试 clean_fields

测试这个函数,咱们只须要在给实例化后的 model 调用这个函数即可:

test_1 = TestValidate.objects.create(even_field=2, name="abc")

test_2 = TestValidate()
test_2.even_field = 1
test_2.name = "abc"
test_2.clean_fields()

在 test_2 调用 clean_fields() 后,零碎会校验 TestValidate 实例化后所有字段的的不非法数据,以及额定的校验操作,即 validators 中定义的校验逻辑

比方在这里 even_field = 1 会被验证不通过,返回一个报错

clean_fields() 函数能够接管 exclude 参数,可用于传入不进行校验的字段名称列表,比方这里咱们设置:

test_2.clean_fields(exclude=["even_field"])

那么即使 even_field 的字段值不非法,也会顺利保留。

2. 测试 validate_unique

在这里咱们设置了 name 字段为 unique 唯一性束缚,也就是说在 TestValidate 表里 name 字段不能存在雷同的值

后面咱们创立了一条 name = "abc" 的值,接着咱们设置 test_2.name = "abc",而后执行:

test_2.name = "abc"
test_2.validate_unique()

零碎会获取 TestValidate 里所有设置了 unique 的字段,而后获取字段对应的值去数据库进行唯一性校验,在咱们下面的例子里设置 name=”abc” 是不通过的。

3. 测试 clean

零碎提供了 clean() 函数,可用于咱们创立自定义的验证操作

比方,咱们设置当 even_field = 4 且 name=” 张三 ” 的时候,这条数据就是不非法的,咱们能够如此先设置 clean() 函数:

class TestValidate(models.Model):
    even_field = models.IntegerField(default=0, validators=[validate_even])
    name = models.CharField(unique=True, max_length=20, default=None)


    def clean(self):
        if self.even_field == 4 and self.name == "张三":
            raise ValidationError("指定 even_field 和 name 不非法")

再执行:

from blog.models import TestValidate

test_3 = TestValidate()
test_3.even_field = 4
test_3.name = "张三"
test_3.clean()

4. 测试 full_clean

如果咱们想在 save() 前都调用一遍下面介绍的校验函数,能够间接执行 full_clean(),它会依照程序挨个调用 clean_fields、clean、validate_unique

full_clean() 接管两个参数,一个 exclude,接管不校验的字段列表,一个 validate_unique,为 布尔型数据,确定是否须要进行唯一性校验

5. 重写 save()

后面咱们会在每次进行 save() 前都手动执行校验函数,咱们能够重写 save(),这样在每次创立和保留一个 model 实例的时候,就不须要手动调用咱们后面的校验函数了,操作示例如下:

class TestValidate(models.Model):
    even_field = models.IntegerField(default=0, validators=[validate_even])
    name = models.CharField(unique=True, max_length=20, default=None)


    def save(self, *args, **kwargs):
        self.clean_fields()
        self.clean()
        self.validate_unique()
        super(TestValidate, self).save(*args, **kwargs)

而 full_clean() 能够间接调用这三个校验函数,所以下面等效于:

def save(self, *args, **kwargs):
    self.full_clean()
    super(TestValidate, self).save(*args, **kwargs)

清空表数据后,咱们能够进行上面的测试:

from blog.models import TestValidate

test_1 = TestValidate.objects.create(even_field=2, name="abc")

test_2 = TestValidate.objects.create(even_field=2, name="abc")  # 会报校验的谬误

test_3 = TestValidate()
test_3.even_field=3
test_3.name = "def"
test_3.save()  # 报校验的谬误 

6. 继承 BaseModel

咱们下面的操作是基于单个 model 的 save() 操作,如果咱们要对每个 model 都实现这种主动进行校验的操作,那么则须要对每个 model 都进行这种 save() 的继承重写操作

如果想要实现每个 model 主动实现这种校验的操作,咱们能够编写一个 BaseModel,在 BaseModel 里重写 save() 操作,而后每个 model 都继承 BaseModel,就能够实现咱们的目标了。

class BaseModel(models.Model):

    class Meta:
        abstract = True

    def save(self, *args, **kwargs):
        self.full_clean()
        super(BaseModel, self).save(*args, **kwargs)


class TestValidate(BaseModel):
    even_field = models.IntegerField(default=0, validators=[validate_even])
    name = models.CharField(unique=True, max_length=20, default=None)

这种操作也能够用于增加根底字段,比方咱们想为每个 model 都增加 updated_time 和 created_time 作为根底字段,用于记录数据写入和更新工夫,能够在 BaseModel 里增加:

class BaseModel(models.Model):
    
    updated_time = models.DateTimeField(auto_now=True)
    created_time = models.DateTimeField(auto_now_add=True)

    class Meta:
        abstract = True    

    def save(self, *args, **kwargs):
        self.full_clean()
        super(BaseModel, self).save(*args, **kwargs)

5、系统验证器介绍

后面介绍的是自定义的验证器,以及如何应用,其实 Django 零碎里为咱们实现了很多根底的验证器:

  • EmailValidator 验证邮箱格局
  • MaxValueValidator 验证最大值
  • MinValueValidator 验证最小值
  • MaxLengthValidator 验证最大长度
  • MinLengthValidator 验证最小长度
  • RegexValidator 验证正则表达式

咱们设置的 model 如下:

class TestValidate(BaseModel):
    even_field = models.IntegerField(default=0, validators=[validate_even])
    name = models.CharField(unique=True, max_length=20, default=None)
    email = models.CharField(max_length=100, default="", validators=[EmailValidator(message="email 不非法 ")])
    count = models.IntegerField(default=8, validators=[MaxValueValidator(limit_value=20), MinValueValidator(limit_value=5)])
    char_str = models.CharField(max_length=100, validators=[MaxLengthValidator(limit_value=90), MinLengthValidator(limit_value=20)], default="")
    telephone = models.CharField(max_length=11, validators=[RegexValidator("1[345678]\d{9}")], default="")

用上了下面这几个自带的验证器,接下来咱们对 email,count,char_str,telephone 几个字段设置不非法的值进行创立:

TestValidate.objects.create(
    even_field=2,
    name="abc",
    email="12314234",
    count=25,
    char_str="abcd",
    telephone="122282883"
)

而后会发现从 email 到 telephone 字段都报了字段值不非法的错,咱们将其挨个修改为 model 里合乎校验规定的数据即可失常创立数据了。

如果想获取更多相干文章,可扫码关注浏览:

正文完
 0