Django笔记:表单验证
对于请求中提交的表单数据,Django中可以使用类的方式进行处理,就像数据库中的表对应于Django中的一个ORM模型类,表单也是对应于一个Form类,Form类主要用于表单数据的验证功能,使得我们在验证表单中的数据时变得非常方便快捷。当然,不使用Form类也是可以处理表单数据的,只是大多数情况下使用Form类会方便很多,也是看个人的使用习惯和工作需要了。
一、Form类
Form
类在from django import forms
中,使用时需要定义一个Form
的子类,相当于将请求的表单数据封装到一个特殊的类中,并自动完成一些数据的验证工作。
1、Form基本使用
Form
子类中的属性名对应于HTML标签中的name
属性值,可以根据表单中的数据类型在类中定义相应的属性字段。
- 每一种字段都有其基本的验证器,如
forms.EmailField
会自动验证接收的数据是否为邮箱格式。 - 可以使用
is_valid()
方法判断是否所有的字段都已通过验证。 - 如果没有通过验证,可以通过表单中的
errors
对象查看错误信息,如errors.get_json_data()
是以字典的形式输出验证失败提示信息。
示例:在app下新建一个forms.py
用于存放所有的表单类
"""forms.py"""
from django import forms
class MessageBoardForm(forms.Form):
"""新建一个Form子类,用于接收表单中的4个值:title,content,email,reply"""
# 接收文本类型数据,error_messages参数用于指定数据不满足相应条件时的错误提示信息
title = forms.CharField(max_length=100, min_length=2, error_messages={"max_length": "最多只能有100个字符!"})
# 接收文本类型数据,widget参数用于指定控件类型,forms.Textarea表示多行文本框控件
content = forms.CharField(widget=forms.Textarea)
# 接收邮箱格式数据
email = forms.EmailField(error_messages={"required": "必须输入邮箱!"})
# 接收布尔类型数据,required参数表示此字段是否为必须的,默认为True,False表示可以不传此参数,即没有接收到此字段也是允许的
reply = forms.BooleanField(required=False)
"""views.py"""
from django.views.generic import View
from django.http import HttpResponse
from .forms import MessageBoardForm
# 定义一个视图类
class IndexView(View):
# 处理post请求
def post(self, request):
# 将表单数据传入Form子类中,如果表单数据有多种类型时,
# 可以直接传入,如form = MessageBoardForm(request.POST, request.FILES)
form = MessageBoardForm(request.POST)
# 判断所有字段是否都通过验证
if form.is_valid():
# 通过验证后,所有字段的数据都存放在cleaned_data中
title = form.cleaned_data.get("title")
content = form.cleaned_data.get("content")
email = form.cleaned_data.get("email")
reply = form.cleaned_data.get("reply")
print(title)
print(content)
print(email)
print(reply)
return HttpResponse("success!")
else:
# get_json_data方法以字典的形式输出没有通过验证的错误信息
print(form.errors.get_json_data())
return HttpResponse("fail!")
2、常用Field字段
常用的Field字段和参数使用如下:
-
CharField
:接收文本数据。常用的参数:-
max_length
:文本的最大长度。 -
min_length
:文本的最小长度。 -
required
:字段是否必须指定,默认是True
。 -
error_messages
:字段验证失败时给出的错误提示信息,需要传入一个字典,字典中需要指定对应验证条件的错误提示信息,如error_messages={"max_length": "最多只能有100个字符!"}
表示指定文本最大长度不满足时给出提示信息。
-
-
EmailField
:接收文本信息,并验证是否为邮箱格式,常用的错误提示类型有:required
、invalid
。 -
FloatField
:接收浮点类型数据,并且验证通过后会将这个字段转换为浮点类型。常用的参数:-
max_value
:最大值。 -
min_value
:最小值。 - 常用的错误提示类型有:
required
、invalid
、max_value
、min_value
。
-
-
IntegerField
:接收整型数据,并且验证通过后会将这个字段转换为整型。常用的参数:-
max_value
:最大值。 -
min_value
:最小值。 - 常用的错误提示类型有:
required
、invalid
、max_value
、min_value
。
-
-
URLField
:接收url格式字符串。常用的错误提示类型有:required
、invalid
。
3、验证器
Form
类中的各个Field
字段其实都有一些基本的验证器,如果表单中的某个字段想要额外添加一些验证功能,可以指定validators
参数给字段添加一些验证器,或者给这个字段定义一个额外的形如clean_[字段名]
自定义验证方法。
内置验证器:内置验证器通过字段的validators
参数指定对应的验证器列表即可,Django内置的验证器都在django.core.validators
中,常用的内置验证器:
-
MaxValueValidator
:最大值。 -
MinValueValidator
:最小值。 -
MaxLengthValidator
:最大长度。 -
MinLengthValidator
:最小长度。 -
EmailValidator
:是否为邮箱格式。 -
URLValidator
:是否为url格式。 -
RegexValidator
:是否符合正则表达式,使用时传入一个正则表达式即可。 -
FileExtensionValidator
:验证文件名后缀是否符合要求,使用时传入一个文件名后缀的列表,如["txt", "csv"]
,表示只允许上传这些类型的文件。
自定义验证:需要针对某个字段进行特殊验证时,可以在Form
表单类中定义一个clean_[字段名]
的方法,就会自动执行这个方法进行验证了,如果不符合要求,直接抛出异常即可,符合要求则返回对应的值。如果想要针对多个字段之间的验证,可以重写clean()
方法,当所有字段的验证都通过后就会执行这个方法。
"""forms.py"""
from django import forms
from django.core import validators
from .models import User
class RegisterForm(forms.Form):
"""定义一个注册功能的Form子类,用来接收注册的相关信息"""
username = forms.CharField(max_length=100)
# 添加一个正则表达式的验证器,message参数表示验证失败时的错误提示信息
telephone = forms.CharField(validators=[validators.RegexValidator(r"1[345678]d{9}", message="请输入正确格式的手机号码!")])
pwd1 = forms.CharField(max_length=16, min_length=6)
pwd2 = forms.CharField(max_length=16, min_length=6)
def clean_telephone(self):
# 当字段的基本验证通过后,会将数据存储在cleaned_data中
telephone = self.cleaned_data.get("telephone")
# 在数据库中查找是否有相同的手机号,User为用户的ORM模型类
exists = User.objects.filter(telephone=telephone).exists()
if exists:
raise forms.ValidationError(message="{}已经被注册!".format(telephone))
# 需要返回处理后的值
return telephone
def clean(self):
# 执行这个方法时表示所有字段都已验证成功,当然,需要先调用父类的clean()方法
cleaned_data = super().clean()
pwd1 = cleaned_data.get("pwd1")
pwd2 = cleaned_data.get("pwd2")
if pwd1 != pwd2:
raise forms.ValidationError(message="两次输入的密码不一致!")
# 返回处理后的数据
return cleaned_data
二、ModelForm类
如果表单提交的信息与已有的ORM模型是一致的,比如提交的信息会直接存储到数据库中,而数据库中对应表在代码中已有相应的ORM模型类了,那么就可以使用ModelForm
类,可以免去我们很多的重复工作,ModelForm
类有许多用法都是和Form
类是类似的,使用时可以参考下。
使用ModelForm
比较简单,需要定义一个ModelForm
的子类,基本使用如下:
- 需要定义一个名为
Meta
的内部类来关联ORM模型类,Meta
类的常用属性如下:-
model
:指定关联的ORM模型类。 -
fields
:指定关联的字段,__all__
表示全部字段,也可以使用列表指定需要的字段。 -
exclude
:指定排除的字段,即除了此属性指定的字段,其他字段都需要关联。 -
error_messages
:指定验证失败时的错误提示信息。
-
"""forms.py"""
from django import forms
from .models import Book
class MyForm(forms.ModelForm):
# 如果想要自定义验证方式,也是和Form类一样的定义方式
def clean_page(self):
page = self.cleaned_data.get("page")
if page > 1000:
raise forms.ValidationError("page不能大于1000!")
return page
class Meta:
# ORM模型类
model = Book
# 指定需要验证的字段,__all__表示所有字段,也可以使用列表将需要的字段放进去即可
fields = "__all__"
# fields = ["title", "page"]
# fields和exclude两个属性必须指定其中一个
# 表示除了这个字段其他字段都需要
# exclude = ["price"]
# 指定验证失败时的错误提示信息
error_messages = {
"title": {
"required": "请输入标题!",
"invalid": "请输入正确格式的标题!"
}
}
- 虽然可以关联到ORM模型类,但是
ModelForm
子类中也是可以定义自己的属性字段的,定义方式也是和Form
子类的定义是一样的,比如提交的表单信息比ORM模型中的字段多的时候就可以这样做。 - 验证时,可以在ORM模型的字段定义中指定
validators
参数,添加额外的验证器即可。如果要对某个字段自定义验证方式时,在ModelForm
子类中像Form
类一样,定义一个clean_[字段名]
的方法来处理即可。
"""models.py"""
from django.db import models
from django.core import validators
class Book(models.Model):
title = models.CharField(max_length=100)
page = models.IntegerField()
# 可以直接在ORM模型字段中添加验证器
price = models.FloatField(validators=[validators.MaxValueValidator(limit_value=250)])
- 当表单的验证都通过之后,可以调用
save()
方法将数据直接保存到数据库中。如果不想直接提交到数据库中,或者还需要给ORM模型中的某些字段指定值,可以使用如user = user_form.save(commit=False)
,指定commit
参数为False
之后,就只是生成对应的模型对象并返回,并不会映射到数据库中。修改完成后,再调用模型对象的save()
方法即可。
"""views.py"""
from django.http import HttpResponse
from django.views.decorators.http import require_POST
from .forms import RegisterForm
# 定义一个视图函数,只允许post的请求方式
@require_POST
def register(request):
# 将post的数据传入ModelForm类中
user_form = RegisterForm(request.POST)
if user_form.is_valid():
# 只是同步ORM模型类,但并不映射到数据库中
user = user_form.save(commit=False)
# 重新指定密码
user.password = user_form.cleaned_data.get("password")
# 保存到数据库中
user.save()
return HttpResponse("success!")
else:
return HttpResponse("fail!")