目录
forms组件渲染标签
<p>forms组件渲染标签的方式1(封装程度过高 扩展性差 主要用于本地测试):</p>
{# {{ form_obj.as_p }}#}
{# {{ form_obj.as_ul }}#}
{# {{ form_obj.as_table }}#}
<p>forms组件渲染标签的方式2(封装程度过低 扩展性高 编写麻烦)</p>
{# {{ form_obj.username.label }}#}
{# {{ form_obj.username }}#}
{# {{ form_obj.age.label }}#}
{# {{ form_obj.age }}#}
{# {{ form_obj.email.label }}#}
{# {{ form_obj.email }}#}
<p>forms组件渲染标签的方式3(封装程度较高 扩展性高 编写简单 推荐使用)</p>
{# {% for form in form_obj %}#}
{# <p>#}
{# {{ form.label }}#}
{# {{ form }}#}
{# </p>#}
{# {% endfor %}#}
注意事项
forms组件之负责渲染获取用户数据的标签 也就意味着form标签与按钮都需要自己写
前端的校验是弱不禁风的 最终都需要后端来校验 所以我们在使用forms组件的时候可以直接取消前端帮我们的校验
<form action="" novalidate>
forms组件展示信息
form表单如何取消浏览器自动添加的数据校验功能(novalidate)
<form action="" method="post" novalidate>
{% for form in form_obj %}
<p>
{{ form.label }}{{ form }}
<span style="color: red;">{{ form.errors.0 }}</span> # 点零只拿错误信息固定文本
</p>
{% endfor %}
<input type="submit" value="提交">
后端不同请求返回的forms对象一定要是相同的变量名
def ab_forms_func(request):
# 1.产生一个空对象
form_obj = MyForm()
if request.method == 'POST':
form_obj = MyForm(request.POST) # request.POST可以看成是一个字典 直接传给forms类校验 字典中无论有多少键值对都没关系 之在乎类中编写的
if form_obj.is_valid(): # 校验数据是否合法
print(form_obj.cleaned_data)
else:
print(form_obj.errors)
# 2.将该对象传递给html文件
return render(request, 'formsPage.html', locals())
{% for form in form_obj %}
<p>
{{ form.label }}
{{ form }}
<span>{{ form.errors.0 }}</span>
</p>
{% endfor %}
针对错误信息的提示可以修改成各国语言
方式1:自定义内容
给字段对象添加errors_messages参数
username = forms.CharField(min_length=3, max_length=8, label='用户名',
error_messages={
'min_length': '用户名最少三个字符',
'max_length': '用户名最多八个字符',
'required': '用户名不能为空'
}
)
方式2:修改系统语言环境
from django.conf import global_settings django内部真正的配置文件
validators案例
from django.core.validators import RegexValidator
phone = forms.CharField(
validators=[
RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
widget案例
# forms.widgets.控制type的类型(attrs=控制各项属性:class id ...)
password = forms.CharField(widget=forms.widgets.PasswordInput(attrs={'class':'form-control'})
)
forms组件校验补充
forms组件针对字段数据的校验 提供了三种类型的校验方式(可以一起使用)
第一种类型:直接填写参数 max_length
第二种类型:使用正则表达式 validators
第三种类型:钩子函数 编写代码自定义校验规则
class MyForm(forms.Form):
username = forms.CharField(min_length=3, max_length=8)
password = forms.CharField(min_length=3, max_length=8)
confirm_pwd = forms.CharField(min_length=3, max_length=8)
钩子函数
钩子函数的作用就是提供自定义的校验方式
局部钩子(校验单个字段)
我们在Form类中定义clean_字段名()
方法,就能够实现对特定字段进行校验。
# 局部钩子:校验用户名是否已存在(一次性只能勾一个人)
'''钩子函数是数据经过了字段第一层参数校验之后才会执行'''
def clean_name(self): # 自动生成的函数名 专门用于对name字段添加额外的校验规则
# 1.先获取用户名
name = self.cleaned_data.get('name')
# 2.判断用户名是否已存在
res = models.User.objects.filter(name=name).first()
if res:
# 3.提示信息
return self.add_error('name', '用户名已存在')
# 4.最后将你勾上来的name返回回去
return name
全局钩子(校验多个字段)
我们在Form类中定义 clean()
方法,就能够实现对字段进行全局校验。
# 全局钩子:校验密码与确认密码是否一致(一次性可以勾多个人)
def clean(self):
# 1.获取多个字段数据
pwd = self.cleaned_data.get('pwd')
confirm_pwd = self.cleaned_data.get('confirm_pwd')
if not pwd == confirm_pwd:
return self.add_error('confirm_pwd', '两次密码不一致 ')
# 最后将整个数据返回
return self.cleaned_data
forms组件参数补充
forms组件源码剖析
我们从is_valid如何校验数据进行分析。
第一步:查看类源码发现只要给类传参self.is_bound肯定是True,重点看self.errors
def is_valid(self):
return self.is_bound and not self.errors
第二步:查看了源码发现self._errors初始化就是None 所以肯定看full_clean方法
@property
def errors(self):
if self._errors is None:
self.full_clean()
return self._errors
第三步:查看full_clean方法,发现主要有3个方法。
def full_clean(self):
self.cleaned_data = {} # 创建了一个存储检查没问题的数据的空字典
self._clean_fields() # 校验数据
self._clean_form() # 封装
self._post_clean() # 返回
第四步:查看self._clean_fields方法
def _clean_fields(self):
for name, field in self.fields.items():# 循环获取字段名和字段对象
if field.disabled: # 字段是否是禁用的
value = self.get_initial_for_field(field, name)
else:
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) # 如果不是禁用,获取字段对应的用户数据,进行校验
try: # 异常捕获
if isinstance(field, FileField): # 文件数据
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
value = field.clean(value) # clean校验的方法
self.cleaned_data[name] = value # 以上校验没有问题,就上传到cleaned_data里
if hasattr(self, 'clean_%s' % name): # 利用反射判断是否拥有clean_%s的方法,就是在获取钩子函数执行,
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value # 钩子函数不报错,添加到cleaned_data里
except ValidationError as e: # 钩子函数报错,添加提示保存信息
self.add_error(name, e)
查看源码发现校验数据的整个过程内部都有异常处理机制
from django.core.exceptions import ValidationError
raise ValidationError('用户名不存在')
# 自己在clean_%s钩子函数主动抛出一个异常,也不会报错,因为钩子函数是交给_clean_fields这个方法里执行的,就算clean_%s报错也是交给了_clean_fields方法里的异常捕获处理。
modelform组件
modelform是form的优化版本使用更简单功能更强大,由于模型类里面的一张张表数据要经常校验,这时候modelform就诞生了,是专门针对模型类使用的。
基本使用
class MyModelForm(forms.ModelForm):
class Meta:
model = models.User # 指定对哪张表做数据校验
fields = '__all__' # 指定对所有字段做数据校验
labels = {} # 给每个字段加名字
widgets = {} # 给每个字段加属性
class Meta下常用参数
model = models.Book # 对应的Model中的类
fields = "__all__" # 字段,如果是__all__,就是表示列出所有的字段
exclude = None # 排除的字段
labels = None # 提示信息
help_texts = None # 帮助提示信息
widgets = None # 自定义插件
error_messages = None # 自定义错误信息
save()方法
每个ModelForm还具有一个save()
方法。 这个方法根据表单绑定的数据创建并保存数据库对象。 ModelForm的子类可以接受现有的模型实例作为关键字参数instance
;如果提供此功能,则save()将更新该实例。 如果没有提供,save() 将创建模型的一个新实例。
class MyModelForm(forms.ModelForm):
class Meta:
model = models.User
fields = '__all__'
def clean_name(self):
name = self.cleaned_data.get('name')
res = models.User.objects.filter(name=name).first()
if res:
self.add_error('name','用户名已存在')
return name
def md(request):
modelform_obj = MyModelForm()
if request.method == 'POST':
# edit_obj = models.User.objects.filter(name='jason').first()
# modelform_obj = MyModelForm(request.POST,instance=edit_obj) 获取修改对象之后再次使用save()方法是修改
modelform_obj = MyModelForm(request.POST)
if modelform_obj.is_valid():
modelform_obj.save() # 保存数据
return render(request,'ab.html',locals())
标签:obj,name,form,补充,self,校验,forms,组件
From: https://www.cnblogs.com/wxlxl/p/17026074.html