Django中的clean()方法和full_clean()方法

前言

clean()是Django在处理数据验证时的常用方法

本博客适合那些知道clean_<filename>方法但是不知道clean()方法的学习者
full_clean()方法用于测试clean()方法的第二种用法,算是补充

clean()

此方法有两种用法,一种用于表单验证,另一种用于模型验证

1、表单验证

在表单验证中,clean()方法用于执行表单最后的验证

他们的执行顺序是这样的

clean()方法是"最后一道防线"

下面来说一下用法

python 复制代码
def clean_<filename>(self):
    """ 其他的验证 """
    return data 

# 与其他验证同级编写
def clean(self):
    clean_data = super().clean()
    """
        这里执行具体的操作
    """
    return clean_data

此处super().clean()得到的是一个已经经过校验的字典

因为clean()方法在最后执行,所以此时得到的是已经经过了前面校验的数据

那么有人可能就会问了,此时已经经过了所有的clean_<filename>方法,那么此时的cleaned_data字典与此时的super().clean()是不是一样的,答案是一样的,他们虽然调用的方式不同,但是他们所指的内存地址是一样的


已知我们在clean_<filename>中抛出raise ValidationError("错误信息")错误信息时

可以在前端中通过ModelForm对象.字段名.errors.0来渲染错误信息

像这样:

html 复制代码
<span style="color: red;">{{ form.password.errors.0 }}</span>

类似的当clean()方法中抛出raise ValidationError("错误信息")时可以

通过.non_field_errors获取错误信息

然后

在前端中这样渲染错误信息:

html 复制代码
<span style="color: red;">{{ form.non_field_errors.0 }}</span>

2、模型验证

在定义模型的时候如果我们想在这个阶段进行数据的验证,那就需要使用到clean()方法的第二种用法

python 复制代码
from datetime import date
from django.core.exceptions import ValidationError

class User(models.Model):
    name = models.CharField(verbose_name="姓名",max_length=128)
    age = models.IntegerField(verbose_name="年龄")
    birthday = models.DateField(verbose_name="生日")
    # --------- 验证区域 -------------
    def clean(self):
        super().clean()
        if self.birthday > date.today():
            raise ValidationError("生日不能大于今天")

注意在这里也要调用super().clean()这样才可以

否则字段里面的验证就不会生效(max_length=128这些字段级验证就会失效)

注意用self.字段名获取字段值

此时抛出的验证错误等同于在ModelForm里面

通过raise ValidationError("")抛出的验证错误

都可以通过.non_field_errors在前端中获取


举个例子:

python 复制代码
def clean(self):
    raise ValidationError("测试错误")

此时他创建的ModelForm在前端中可以通过

html 复制代码
<span style="color: red;">{{ form.confirm_password.errors.0 }}</span>

来获取错误


总结一下就是在模型中的clean()方法抛出的错误的获取方式就

等同于在ModelForm中的clean()方法抛出的错误

都可以通过.non_field_errors获取

full_clean()

已知通过.save()会执行你在模型里面定义的验证规则以及在ModelForm中定义的验证规则
full_clean()方法则会只执行你在models.py中定义的相关验证

举个例子就明白了
models.py

python 复制代码
class User(models.Model):
    name = models.CharField(verbose_name="姓名",max_length=128)
    age = models.IntegerField(verbose_name="年龄")
    birthday = models.DateField(verbose_name="生日")
    def clean(self):
        super().clean()
        if self.birthday > date.today():
            raise ValidationError("生日不能大于今天")

编写一个测试用例

python 复制代码
admin_test = User(name="张三",age=21,birthday='2027-1-1')
try:
    admin_test.full_clean()
    admin_test.save()
except ValidationError as e:
    for field, errors in e.message_dict.items():
        print(f"{field}: {errors}")

此时控制台打印

python 复制代码
__all__: ['生日不能大于今天']

他只会执行上述的models.py中的验证

注意:full_clean()如果通过了就什么都不会返回

但是如果没有通过验证他就会抛出raise ValidationError
.save()方法可以用于ModelForm对象保存数据到数据库

也可以用于模型对象保存数据到数据库

python 复制代码
user = models.User.objects.create(
    username='john',
    email='john@example.com', 
    password='password123'
)
# 等价于
user_object = User(
    username='john',
    email='john@example.com',
    password='password123'
)
user_object.save()  

但是不会进行clean()验证,只会执行字段级别的验证,比如max_length=128这种验证

上述代码两段等价代码

只会执行标红部分的验证

相关推荐
牛奔21 分钟前
Go 如何避免频繁抢占?
开发语言·后端·golang
寻星探路4 小时前
【深度长文】万字攻克网络原理:从 HTTP 报文解构到 HTTPS 终极加密逻辑
java·开发语言·网络·python·http·ai·https
想用offer打牌5 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
KYGALYX7 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了7 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
ValhallaCoder7 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
爬山算法7 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
猫头虎8 小时前
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题
java·开发语言·jvm·spring boot·python·开源·maven
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
八零后琐话8 小时前
干货:程序员必备性能分析工具——Arthas火焰图
开发语言·python