Django高级之forms组件
forms组件之校验字段
第一步:定义一个类,继承forms.Form
第二步:在类中写字段,要校验的字段,字段属性就是校验规则
第三步:实例化得到一个Form对象,把要校验的数据传入
第四步:调用register_form.is_valid()校验,校验通过就是True
第五步:校验通过有register_form.cleaned_data
第六步:校验不通过 register_form.errors
forms组件
-数据校验
-渲染页面
-错误信息
-局部全局钩子
-使用步骤:
-写一个类,继承Form类
-写字段,字段参数(限制该字段的长短)
-错误信息中文:字段参数
-widget:控制生成标签的属性
-视图函数中:
-实例化得到form对象时,把要校验的数据传入
-is_valid():clean_data和errors就有值了
-如果校验通过就存,不通过就给页面提示
-渲染页面
-for循环的方式渲染页面(在标签前后可以再加标签)
-局部钩子
-def clean_字段名(self):
-校验规则
-如果通过,return 值
-如果不通过,抛异常
-全局钩子(多个字段校验)
-def clean(self):
-如果通过,return clean_data
-如果不通过,抛异常
#定义类
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError
class RegisterForm(forms.Form):
name = forms.CharField(max_length=8, min_length=3, label='用户名')
password = forms.CharField(max_length=8, min_length=3, label='密码')
re_password = forms.CharField(max_length=8, min_length=3, label='确认密码')
email = forms.EmailField(label='邮箱')
#在视图中使用
register_form = RegisterForm(request.POST)
if register_form.is_valid():
# 校验通过,存
# 取出校验通过的数据
print('校验通过')
print(register_form.cleaned_data)
else:
# 校验不通过
print('校验不通过')
print(register_form.errors)
forms组件之渲染标签
后端
def register(request):
if request.method == 'GET':
# 实例化生成一个空form对象
register_form = RegisterForm()
return render(request, 'register.html', {'form',register_form})
渲染一
<h2>通过form自动渲染一</h2>
<form action="" method="post">
<p>用户名 {{ form.name }}</p>
<p>密码 {{ form.password }}</p>
<p>确认密码 {{ form.re_password }}</p>
<p>邮箱 {{ form.email }}</p>
<input type="submit" value="提交">
</form>
渲染 二
<h2>通过form自动渲染二(基本用这种)</h2>
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form action="" method="post" novalidate>
{% for item in form %}
<div class="form-group">
<p>{{ item.label }}{{ item }} <span style="color: red">{{ item.errors.0 }}</span></p>
</div>
{% endfor %}
<input type="submit" value="提交"><span style="color: red">{{ error }}</span>
</form>
</div>
</div>
</div>
渲染 三
#自动渲染
<form action="" method="post">
{{ form.as_p }}
{# {{ form.as_table }}#}
{# {{ form.as_ul }}#}
</form>
forms组件之渲染错误信息
前端
<h2>通过form自动渲染二(基本用这种)</h2>
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form action="" method="post" novalidate>
{% for item in form %}
<div class="form-group">
<p>{{ item.label }}{{ item }} <span style="color: red">{{ item.errors.0 }}</span></p>
</div>
{% endfor %}
<input type="submit" value="提交"><span style="color: red">{{ error }}</span>
</form>
</div>
</div>
</div>
后端
class RegisterForm(forms.Form):
name = forms.CharField(max_length=8, min_length=3, label='用户名',
error_messages={'max_length': '最长为8', 'min_length': '最短为3'},
widget=widgets.TextInput(attrs={'class': 'form-control'}))
password = forms.CharField(max_length=8, min_length=3, label='密码',
error_messages={'required': '该字段必填'},
widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
re_password = forms.CharField(max_length=8, min_length=3, label='确认密码',
widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
email = forms.EmailField(label='邮箱',
error_messages={'required': '必填', 'invalid': '必须是邮箱格式'},
widget=widgets.TextInput(attrs={'class': 'form-control'}))
def forms(request):
if request.method == 'GET':
register_from = RegisterForm()
return render(request, 'forms.html', {'form': register_from})
else:
register_form = RegisterForm(request.POST)
if register_form.is_valid():
# 校验通过,存
# 取出校验通过的数据
print('校验通过')
print(register_form.cleaned_data)
register_form.cleaned_data.pop('re_password')
models.User.objects.create(**register_form.cleaned_data)
else:
# 校验不通过
print('校验不通过')
print(register_form.errors)
return render(request, 'forms.html', {'form': register_form})
models数据库
class User(models.Model):
name = models.CharField(max_length=32)
password = models.CharField(max_length=32)
email = models.EmailField(null=True) #新建不需要null
forms组件全局钩子,局部钩子
后端
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError
class RegisterForm(forms.Form):
name = forms.CharField(max_length=8, min_length=3, label='用户名',
error_messages={'max_length': '最长为8', 'min_length': '最短为3'},
widget=widgets.TextInput(attrs={'class':'form-control'}))
password = forms.CharField(max_length=8, min_length=3, label='密码',
error_messages={'required': '该字段必填'},
widget=widgets.PasswordInput(attrs={'class':'form-control'}))
re_password = forms.CharField(max_length=8, min_length=3, label='确认密码',
widget=widgets.PasswordInput(attrs={'class':'form-control'}))
email = forms.EmailField(label='邮箱',
error_messages={'required': '必填', 'invalid': '必须是邮箱格式'},
widget=widgets.TextInput(attrs={'class':'form-control'}))
def clean_name(self):#name字段的局部钩子
# 校验名字不能以sb开头
name=self.cleaned_data.get('name')
if name.startswith('sb'):
# 校验不通过,必须抛异常,
raise ValidationError('不能以sb开头')
else:#校验通过,返回name对应的值
return name
def clean(self): # 全局钩子
password=self.cleaned_data.get('password')
re_password=self.cleaned_data.get('re_password')
if re_password==password:
#校验通过
return self.cleaned_data
else:
raise ValidationError('两次密码不一致')
def clean(self): # 全局钩子
password=self.cleaned_data.get('password')
re_password=self.cleaned_data.get('re_password')
if not re_password==password:
raise ValidationError('两次密码不一致')
from app01 import models
def register(request):
if request.method == 'GET':
# 生成一个空form对象
register_form = RegisterForm()
return render(request, 'register.html', {'form': register_form})
else:
# 实例化得到对象,传入要校验的数据
# register_form=RegisterForm(data=request.POST)
register_form = RegisterForm(request.POST)
if register_form.is_valid():
# 校验通过,存
# 取出校验通过的数据
print('校验通过')
print(register_form.cleaned_data)
register_form.cleaned_data.pop('re_password')
models.User.objects.create(**register_form.cleaned_data)
return HttpResponse('ok')
else:
# 校验不通过
print('校验不通过')
print(register_form.errors)
error=register_form.errors.get('__all__')[0]
print(type(register_form.errors.as_json))
from django.forms.utils import ErrorDict
# name_error=register_form.errors.get('name')[0]
return render(request, 'register.html', {'form': register_form,'error':error})
前端
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form action="" method="post" novalidate>
{% for item in form %}
<div class="form-group">
<p>{{ item.label }}{{ item }} <span style="color: red">{{ item.errors.0 }}</span></p>
</div>
{% endfor %}
<input type="submit" value="提交"><span style="color: red">{{ error }}</span>
</form>
</div>
</div>
</div>
forms组件源码分析
1 为什么局部钩子要写成 clean_字段名,为什么要抛异常
2 入口在 is_valid()
3 校验流程
-先校验字段自己的规则(最大,最小,是否必填,是不是合法)
-校验局部钩子函数
-全局钩子校验
4 流程
-is_valid()---》return self.is_bound and not self.errors
-self.errors:方法包装成了数据数据
-一旦self._errors有值,就不进行校验了(之前调用过了)
-self.full_clean():核心
self._errors = ErrorDict()
if not self.is_bound:
return
self.cleaned_data = {}
self._clean_fields()
self._clean_form()
self._post_clean()
-self._clean_fields():核心代码,局部钩子执行位置
value = field.clean(value)# 字段自己的校验规则
self.cleaned_data[name] = value #把校验后数据放到cleaned_data
if hasattr(self, 'clean_%s' % name): # 判断有没有局部钩子
value = getattr(self, 'clean_%s' % name)() #执行局部钩子
self.cleaned_data[name] = value #校验通过,把数据替换一下
# 如果 校验不通过,会抛异常,会被捕获,捕获后执行
self.add_error(name, e)
- def _clean_form(self):#全局钩子执行位置
def _clean_form(self):
try:
#如果自己定义的form类中写了clean,他就会执行
cleaned_data = self.clean()
except ValidationError as e:
self.add_error(None, e)

浙公网安备 33010602011771号