这些基本你的校验功能,不足以满足我们日常的需要,用户名不允许出现敏感字符,电话号码的验证,等等。
正则校验器(validators)
name = form.CharField(
label=‘用户名:‘,
required=True, #必须填入内容的设置,默认为True
initial=‘dong‘, #设置初始值
min_length=6,
max_length=12,
help_text=‘用户名不能有特殊字符‘,
# 一个参数正则的匹配规则,第二参数不满足这个匹配规则报的错误信息
validators=[RegexValidator(r‘^金ping梅‘, ‘必须以金ping梅开头‘),
RegexValidator(r‘xx$‘, ‘必须以xx结尾‘),],
errpr_messages={‘min_length‘: ‘太短了‘, ‘max_length‘: ‘太长了‘,
‘required‘: ‘必须填写内容‘},
widget=forms.widgets.TextInput,
)
这种正则校验器比较局限,用起来相对麻烦。
自定制函数校验
(注意:模块的引入要向下面的规则写)
import re
?
from django.shortcuts import render, HttpResponse
from django import forms
from django.core.validators import ValidationError
?
?
def moblie_validate(value):
# 我们这里就给name字段设置这个函数的的匹配规则
# 那么这个value就是name字段实际得到的数据
mobile_re = re.compile(r‘^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$‘)
if not mobile_re.match(value):
raise ValidationError(‘手机号格式错误‘) # 自定义验证规则的时候,如果不符合你的规则,需要自己发起错误
?
class RegisterForm(forms.Form):
"""
form组件生成前端的标签写法,与models构建的表结构非常相似
"""
name = forms.CharField(
label=‘用户名:‘,
required=True, # 必须填入内容的设置,默认为True
initial=‘dong‘, # 设置初始值
min_length=8,
max_length=14,
help_text=‘用户名不能有特殊字符‘,
# validators=[RegexValidator(r‘^金ping梅‘, ‘必须以金ping梅开头‘), RegexValidator(r‘xxx$‘, ‘必须以xxx结尾‘)],
error_messages={‘min_length‘: ‘太短了‘, ‘max_length‘: ‘太长了‘, ‘required‘: ‘必须填写内容‘},
validators=[moblie_validate],
widget=forms.widgets.TextInput(),
)
?
password = forms.CharField(
label=‘密码:‘,
min_length=6,
help_text=‘密码不得少于8位‘,
# widget这个功能可以当成一个工具,这个工具就是确认标签类型以及i增加标签属性的
error_messages={‘min_length‘: ‘太短了‘},
widget=forms.widgets.PasswordInput,
)
form组件给你提供了另一个自定制校验规则的接口:局部钩子,全局钩子
局部钩子
比如,你的用户名不能出现一些敏感词汇,敏感词汇有:
东京热,苍?师,?ping梅,..... 这些?正则匹配有点??不从?了。所以我们就得?钩 ?去解决。
局部钩子是针对某个字段校验的。
import re
?
from django.shortcuts import render, HttpResponse
from django import forms
from django.core.validators import ValidationError
?
?
class RegisterForm(forms.Form):
"""
form组件生成前端的标签写法,与models构建的表结构非常相似
"""
?
name = forms.CharField(
label=‘用户名:‘,
required=True, # 必须填入内容的设置,默认为True
initial=‘dong‘, # 设置初始值
min_length=8,
max_length=14,
help_text=‘用户名不能有特殊字符‘,
# validators=[RegexValidator(r‘^金ping梅‘, ‘必须以金ping梅开头‘), RegexValidator(r‘xxx$‘, ‘必须以xxx结尾‘)],
error_messages={‘min_length‘: ‘太短了‘, ‘max_length‘: ‘太长了‘, ‘required‘: ‘必须填写内容‘},
# validators=[moblie_validate],
widget=forms.widgets.TextInput(),
)
?
password = forms.CharField(
label=‘密码:‘,
min_length=6,
help_text=‘密码不得少于8位‘,
# widget这个功能可以当成一个工具,这个工具就是确认标签类型以及i增加标签属性的
error_messages={‘min_length‘: ‘太短了‘},
widget=forms.widgets.PasswordInput,
)
?
def clean_name(self): # 针对于name字段做一个用于校验的局部钩子
print(‘进入clean_name局部钩子‘)
sensitive_vocabulary = [‘京东热‘, ‘苍老师‘, ‘金ping梅‘]
name_value = self.cleaned_data[‘name‘]
for i in sensitive_vocabulary:
if i in name_value:
raise ValidationError(f‘含有敏感词汇{i}‘)
else:
return self.cleaned_data[‘name‘] # 必须将所有的验证过后的数据返回
?
注意:
局部钩?命名:clean_字段名
如果有错误:主动抛出异常 ValidationError
校验成功之后,必须返回self.cleaned_data[‘字段名‘]
全局钩子
全局钩子就是对form类中的所有的字段做一个对比验证, 或者横向验证。我们一般注册时,都需要输入用户名、密码。再次输入密码。这样的需求在全局钩子中做一些验证比较合适。
import re
?
from django.shortcuts import render, HttpResponse
from django import forms
from django.core.validators import ValidationError
?
?
?
class RegisterForm(forms.Form):
"""
form组件生成前端的标签写法,与models构建的表结构非常相似
"""
?
name = forms.CharField(
label=‘用户名:‘,
required=True, # 必须填入内容的设置,默认为True
initial=‘dong‘, # 设置初始值
min_length=8,
max_length=14,
help_text=‘用户名不能有特殊字符‘,
# validators=[RegexValidator(r‘^金ping梅‘, ‘必须以金ping梅开头‘), RegexValidator(r‘xxx$‘, ‘必须以xxx结尾‘)],
error_messages={‘min_length‘: ‘太短了‘, ‘max_length‘: ‘太长了‘, ‘required‘: ‘必须填写内容‘},
# validators=[moblie_validate],
widget=forms.widgets.TextInput(),
)
?
password = forms.CharField(
label=‘密码:‘,
min_length=6,
help_text=‘密码不得少于8位‘,
# widget这个功能可以当成一个工具,这个工具就是确认标签类型以及i增加标签属性的
error_messages={‘min_length‘: ‘太短了‘},
widget=forms.widgets.PasswordInput,
)
confirm_password = forms.CharField(
label=‘再次密码:‘,
min_length=6,
help_text=‘密码不得少于8位‘,
# widget这个功能可以当成一个工具,这个工具就是确认标签类型以及i增加标签属性的
error_messages={‘min_length‘: ‘太短了‘},
widget=forms.widgets.PasswordInput,
)
?
def clean_name(self): # 针对于name字段做一个用于校验的局部钩子
print(‘进入clean_name局部钩子‘)
sensitive_vocabulary = [‘京东热‘, ‘苍老师‘, ‘金ping梅‘]
name_value = self.cleaned_data[‘name‘]
for i in sensitive_vocabulary:
if i in name_value:
raise ValidationError(f‘含有敏感词汇{i}‘)
else:
return self.cleaned_data # 必须将所有的验证过后的数据返回
?
def clean(self): # 全局钩子
v1 = self.cleaned_data[‘password‘],
v2 = self.cleaned_data[‘confirm_password‘],
if v1 == v2:
return self.cleaned_data # 验证成功必须返回
else:
# confirm_password添加错误信息
self.add_error(‘confirm_password‘, ‘两次密码不一样‘)
# 主动抛出一个异常
raise ValidationError(‘两次密码不一样‘)
将增加的那个??,的前端的标签,利?form组件?动?成,并且可以进?简单的验证。
1、在views创建form组件
class BookFrom(forms.Form):
"""
form组件生成前端的标签
"""
book_name = forms.CharField(
label=‘书籍名称:‘,
required=True,
initial=‘书名‘,
min_length=1,
max_length=20,
help_text=‘书名不能有特殊字符‘,
error_messages={‘min_length‘: ‘太短了‘, ‘max_length‘: ‘太长了‘, ‘required‘: ‘必须填写内容‘},
widget=forms.widgets.TextInput(),
)
book_date = forms.CharField(
label=‘出版日期:‘,
widget=forms.widgets.TextInput(attrs={‘type‘: ‘date‘}), # 标签类型
)
book_price = forms.DecimalField(
label=‘书籍价格:‘,
max_digits=5,
decimal_places=2,
help_text=‘人民币(¥)‘,
widget=forms.widgets.TextInput(attrs={‘type‘: ‘number‘})
)
book_publish = forms.ChoiceField(
label=‘出版社:‘,
initial=1,
choices=((1, ‘xx出版社‘), (2, ‘qq出版社‘), (3, ‘aa出版社‘)),
widget=forms.widgets.Select(), # 标签类型
)
book_author = forms.MultipleChoiceField(
label=‘作者:‘,
initial=(1, 2), # 设置初始值
choices=((1, ‘张三‘), (2, ‘李四‘), (3, ‘王五‘)),
widget=forms.widgets.SelectMultiple(), # 标签类型
)
2、更改前端页面
{% load static %}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="{% static ‘bootstrap.min.css‘ %}" rel="stylesheet">
<link href="{% static ‘dashboard.css‘ %}" rel="stylesheet">
<style>
#frame {
width: 350px;
height: 400px;
border: 1px solid black;
margin: 180px auto;
}
?
div {
margin-top: 20px;
margin-left: 20px;
}
?
.pull {
margin-top: 50px;
margin-left: 150px;
}
?
select {
margin-left: 17px;
}
</style>
</head>
<body>
<h1>添加书籍页面</h1>
<div class="row">
<div class="col-md-5 col-md-offset-3">
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
<div>
<label for="">{{ form_obj.book_name.label }}</label>
{{ form_obj.book_name }}
{{ form_obj.book_name.help_text }}
</div>
<div>
<label for="">{{ form_obj.book_date.label }}</label>
{{ form_obj.book_date }}
</div>
<div>
<label for="">{{ form_obj.book_price.label }}</label>
{{ form_obj.book_price }}
{{ form_obj.book_price.help_text }}
</div>
<div>
<label for="">{{ form_obj.book_publish.label }}</label>
{{ form_obj.book_publish }}
</div>
<div>
<label for="">{{ form_obj.book_author.label }}</label>
{{ form_obj.book_author }}
</div>
</form>
</div>
</div>
?
?
</body>
</html>
增加bootstrap样式:
在BookFrom类里面写上这个函数:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
print(self.fields)
for obj in self.fields.values():
obj.widget.attrs.update({‘class‘: ‘form-control‘})
点击标签名称:inptu自动获取光标
让label的for = {{ form_obj.字段名.id_for_label }}
{% load static %}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="{% static ‘bootstrap.min.css‘ %}" rel="stylesheet">
<link href="{% static ‘dashboard.css‘ %}" rel="stylesheet">
<style>
#frame {
width: 350px;
height: 400px;
border: 1px solid black;
margin: 180px auto;
}
?
div {
margin-top: 20px;
margin-left: 20px;
}
?
.pull {
margin-top: 50px;
margin-left: 150px;
}
?
select {
margin-left: 17px;
}
</style>
</head>
<body>
<h1>添加书籍页面</h1>
<div class="row">
<div class="col-md-5 col-md-offset-3">
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
<div>
<label for="{{ form_obj.book_name.id_for_label }}">{{ form_obj.book_name.label }}</label>
{{ form_obj.book_name }}
{{ form_obj.book_name.help_text }}
</div>
<div>
<label for="{{ form_obj.book_date.id_for_label }}">{{ form_obj.book_date.label }}</label>
{{ form_obj.book_date }}
</div>
<div>
<label for="{{ form_obj.book_price.id_for_label }}">{{ form_obj.book_price.label }}</label>
{{ form_obj.book_price }}
{{ form_obj.book_price.help_text }}
</div>
<div>
<label for="{{ form_obj.book_publish.id_for_label }}">{{ form_obj.book_publish.label }}</label>
{{ form_obj.book_publish }}
</div>
<div>
<label for="{{ form_obj.book_author.id_for_label }}">{{ form_obj.book_author.label }}</label>
{{ form_obj.book_author }}
</div>
</form>
</div>
</div>
?
?
</body>
</html>
3、获取数据的真是出版社以及作者数据
class BookFrom(forms.Form): """ form组件生成前端的标签 """ book_name = forms.CharField( label=‘书籍名称:‘, required=True, initial=‘书名‘, min_length=1, max_length=20, help_text=‘书名不能有特殊字符‘, error_messages={‘min_length‘: ‘太短了‘, ‘max_length‘: ‘太长了‘, ‘required‘: ‘必须填写内容‘}, widget=forms.widgets.TextInput(), ) book_date = forms.CharField( label=‘出版日期:‘, widget=forms.widgets.TextInput(attrs={‘type‘: ‘date‘}), # 标签类型 ) book_price = forms.DecimalField( label=‘书籍价格:‘, max_digits=5, decimal_places=2, help_text=‘人民币(¥)‘, widget=forms.widgets.TextInput(attrs={‘type‘: ‘number‘}) ) book_publish = forms.ModelChoiceField( label=‘出版社:‘, initial=1, # choices=((1, ‘xx出版社‘), (2, ‘qq出版社‘), (3, ‘aa出版社‘)), queryset=models.Publish.objects.all(), widget=forms.widgets.Select(), # 标签类型 ) book_author = forms.ModelMultipleChoiceField( label=‘作者:‘, initial=(1, 2), # 设置初始值 # choices=((1, ‘张三‘), (2, ‘李四‘), (3, ‘王五‘)), queryset=models.Author.objects.all(), widget=forms.widgets.SelectMultiple(), # 标签类型 ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) print(self.fields) for obj in self.fields.values(): obj.widget.attrs.update({‘class‘: ‘form-control‘})
4、将post提交的数据写入数据库
def add(request): form_obj = BookFrom() if request.method == ‘GET‘: return render(request, ‘add.html‘, {‘form_obj‘: form_obj}) else: form_obj = BookFrom(request.POST) if form_obj.is_valid(): authors = form_obj.cleaned_data.pop(‘author‘) book_obj = models.Book.objects.create(**form_obj.cleaned_data) book_obj.author.add(*authors) return redirect(‘home‘) else: return render(request, ‘add.html‘, {‘form_obj‘: form_obj})
23.Django(form组件 自定制校验规则、钩子、更改图书管理系统)
原文:https://www.cnblogs.com/muyangxiaodong/p/13209985.html