ModelForm表单
Django中使用Form和ModelForm两个组件实现表单,这里只介绍ModelForm
。
models.py代码如下:
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
page = models.IntegerField()
price = models.FloatField()
class User(models.Model):
username = models.CharField(max_length=100)
password = models.CharField(max_length=16)
telephone = models.CharField(max_length=11)
新建forms.py,代码如下:
from django import forms
from .models import Book
class AddBookForm(forms.ModelForm):
class Meta:
model = Book # 模型表单引用的是哪个模型
fields = "__all__" # 引用模型中的全部字段
views.py代码如下:
from django.http import HttpResponse
from .forms import AddBookForm
def add_book(request):
form = AddBookForm(request.POST)
if form.is_valid():
title = form.cleaned_data.get("title")
page = form.cleaned_data.get("page")
price = form.cleaned_data.get("price")
print("title:%s" % title)
print("page:%s" % page)
print("price:%s" % price)
return HttpResponse("success1")
else:
print(form.errors.get_json_data())
return HttpResponse("FAIL")
其中cleaned_data
属性实现合法数据,不合法的数据会被cleaned_data
自动清洗掉。
在postman中向’http://127.0.0.1:8000/front/add_book/'发送post请求,输入三个参数,能够正确请求成功。少输入参数或参数的值类型不对,也会给出错误提示。
上面的forms中是引用了模型中的全部字段,也可以引用部分字段。
指定引用的字段
from django import forms
from .models import Book
class AddBookForm(forms.ModelForm):
class Meta:
model = Book # 模型表单引用的是哪个模型
fields = ["title", "page"] # 指定要引用模型中的字段
排除不需要的字段
from django import forms
from .models import Book
class AddBookForm(forms.ModelForm):
class Meta:
model = Book # 模型表单引用的是哪个模型
exclude = ["price"] # 排除不需要引用的字段
在上面的代码中,添加图书,运行if form.is_valid():
通过时,不需要进行繁琐的赋值传值,可以直接调用save()
方法进行保存。这个方法要在clean
没有问题后才能使用(clean后的数据都是符合规则的有效数据)。如果在调用save方法是,传入了一个参数commit=False
,那么只会生成这个模型的对象,而不会把这个对象直接插入到数据库中。(执行save()
方法有一个前提,就是表单所需的数据都已经涵盖了对应模型的数据,否则有可能会因为字段缺失导致保存失败。)
def add_book(request):
form = AddBookForm(request.POST)
if form.is_valid():
# title = form.cleaned_data.get("title")
# page = form.cleaned_data.get("page")
# price = form.cleaned_data.get("price")
#
# print("title:%s" % title)
# print("page:%s" % page)
# print("price:%s" % price)
form.save()
return HttpResponse("success1")
else:
print(form.errors.get_json_data())
return HttpResponse("FAIL")
表单验证数据
常用的Field
使用Field可以是对数据验证的第一步期望提交过来的数据是什么类型,那么就使用什么类型的Field。
CharField
用来接收文本。
参数:
max_length
:字段值的最大长度;min_length
:字段值的最小长度;required
:字段是否是必须的。默认是必须的;error_messages
:在验证失败的时候,给出错误信息;
EmailField
用来接收邮件,会自动验证邮件是否合法。
错误信息的key:required
、invalid
FloatField
用来接收浮点类型,并且如果验证通过后,会将这个字段的值转为浮点类型。
max_length
:字段值的最大长度;min_length
:字段值的最小长度;
错误信息的key:required
、invalid
、max_value
、min_value
IntegerField
用来接收整型,并且验证通过后,会将这个字段的值转换为整型。
max_length
:字段值的最大长度;min_length
:字段值的最小长度;
错误信息的key:required
、invalid
、max_value
、min_value
URLField
用来接收url格式的字符串。
错误信息的key:required
、invalid
forms.py
from django import forms
class MyForm(forms.Form):
email = forms.EmailField()
views.py
from django.http import HttpResponse
from django.views.generic import View
from django.http import HttpResponse
from .forms import MyForm
def index(request):
return HttpResponse("success")
class IndexView(View):
def get(self, request):
return HttpResponse("get success")
def post(self, request):
form = MyForm(request.POST)
if form.is_valid():
return HttpResponse("post success")
else:
print(form.errors.get_json_data())
return HttpResponse('post fail')
使用postman创建请求,url:http://127.0.0.1:8000/front1/index/ ,参数是email
email为空时,发送请求
{'email': [{'message': '这个字段是必填项。', 'code': 'required'}]}
email填入不符合规则的字符串,发送请求
{'email': [{'message': '输入一个有效的 Email 地址。', 'code': 'invalid'}]}
可以在forms.py中自定义错误提示的内容
from django import forms
class MyForm(forms.Form):
email = forms.EmailField(
error_messages={"required": "邮箱不能为空_plscript", "invalid": "邮箱格式不正确,请输入正确的邮箱_plscript"})
再次发送上面的两个请求
{'email': [{'message': '邮箱不能为空_plscript', 'code': 'required'}]}
{'email': [{'message': '邮箱格式不正确,请输入正确的邮箱_plscript', 'code': 'invalid'}]}
常用的验证器
在验证某个字段的时候,可以传递一个validators
参数用来指定验证器,进一步对数据进行过滤。验证器有很多,不过很多验证器其实已经通过Field或者一些参数就可以指定了。比如EmailValidator
,可以同EmailField
来指定;比如MaxValueValidator
可以通过max——value
参数来指定。常用的验证器:
MaxValueValidator
:验证最大值;MinValueValidator
:验证最小值;MinLengValidator
:验证最小长度;MaxLengValidator
:验证最大长度;EmailValidator
:验证是否是邮箱格式;URLValidator
:验证是否是URL格式;RegexValidator
:若还需要更复杂的验证,可以通过正则表达式来验证。
在上面的例子基础上修改forms.py
from django import forms
from django.core import validators
class MyForm(forms.Form):
# email = forms.EmailField(
# error_messages={"required": "邮箱不能为空_plscript", "invalid": "邮箱格式不正确,请输入正确的邮箱_plscript"})
email = forms.CharField(validators=[validators.EmailValidator(message="邮箱验证失败,请输入有效的邮箱")])
telephone = forms.CharField(validators=[validators.RegexValidator(r'1[3456789]\d{9}', message="请输入正确的手机号码!")])
用postman发送请求
{'email': [{'message': '邮箱验证失败,请输入有效的邮箱', 'code': 'invalid'}]}
{'telephone': [{'message': '请输入正确的手机号码!', 'code': 'invalid'}]}
自定义验证
对字段进行自定义方法验证时,新建验证方法以’clean_’开头加上要验证的字段名。当views视图中执行到if form.is_valid():
时会自动执行自定义方法clean_字段名
。
新建register app,
models.py
from django.db import models
class User(models.Model):
username = models.CharField(max_length=100)
telephone = models.CharField(max_length=11, null=True, blank=True)
views.py
from django.views.generic import View
from django.http import HttpResponse
from .forms import RegisterForm
from .models import User
class RegisterView(View):
def get(self, request):
return HttpResponse("get success")
def post(self, request):
form = RegisterForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get("username")
telephone = form.cleaned_data.get("telephone")
User.objects.create(username=username, telephone=telephone)
return HttpResponse("注册成功!")
else:
print(form.errors.get_json_data())
return HttpResponse("注册失败!")
forms.py
from django import forms
from django.core import validators
from .models import User
class RegisterForm(forms.Form):
username = forms.CharField(max_length=100)
telephone = forms.CharField(
validators=[validators.RegexValidator(r'1[3456789]\d{9}', message="请输入正确的手机号码!")])
pwd = forms.CharField(max_length=16, min_length=6)
verify_pwd = forms.CharField(max_length=16, min_length=6)
# 对字段进行自定义方法验证时,新建验证方法以'clean_'开头加上要验证的字段名
# 当views视图中执行到'if form.is_valid():'时会自动执行自定义方法'clean_字段名'
# 下面的方法判断提交的手机号码是否已经被注册了
def clean_telephone(self):
telephone = self.cleaned_data.get('telephone')
exists = User.objects.filter(telephone=telephone).exists()
if exists:
raise forms.ValidationError(message="%s已经被注册!" % telephone)
return telephone
# 重写clean方法,执行到clean()方法,表示之前每个字段都已经验证ok的
def clean(self):
cleaned_data = super().clean()
pwd = cleaned_data.get('pwd')
verify_pwd = cleaned_data.get('verify_pwd')
if pwd != verify_pwd:
raise forms.ValidationError(message="两次密码输入不一致")
return cleaned_data
执行
{'telephone': [{'message': '这个字段是必填项。', 'code': 'required'}]}
{'telephone': [{'message': '13888888888已经被注册!', 'code': ''}]}
{'__all__': [{'message': '两次密码输入不一致', 'code': ''}]}
提取错误信息
如果验证失败了,那么有一些错误信息是需要传给前端的。可以通过下面的属性来获取:
form.errors
:这个属性获取的错误信息是一个包含了html标签的错误信息;form.errors.get_json_data()
:这个方法获取到的是一个字典类型的错误信息。将某个字段的名字作为key,错误信息作为其值;form.as_json()
:这个方法是将form.get_json_data()
返回的字典dump成json格式的字符串。
在forms.py中封装一个精简错误信息的方法
def get_errors(self):
error_datas = self.errors.get_json_data()
new_errors = {}
for key, message_dicts in error_datas.items():
messages = []
for message in message_dicts:
message = message['message']
messages.append(message)
new_errors[key] = messages
return new_errors
在views.py中将输出错误提示的代码替换成上面的方法
class RegisterView(View):
def get(self, request):
return HttpResponse("get success")
def post(self, request):
form = RegisterForm(request.POST)
if form.is_valid():
username = form.cleaned_data.get("username")
telephone = form.cleaned_data.get("telephone")
User.objects.create(username=username, telephone=telephone)
return HttpResponse("注册成功!")
else:
# print(form.errors.get_json_data())
print(form.get_errors())
return HttpResponse("注册失败!")
{'telephone': ['请输入正确的手机号码!'], 'pwd': ['确保该变量至少包含 6 字符(目前字符数 4)。'], 'verify_pwd': ['确保该变量至少包含 6 字符(目前字符数 4)。']}