首页 > 编程语言 >jango框架:forms组件渲染标签、forms组件展示信息、forms组件校验补充、forms组件参数补充、forms组件源码剖析、modelform组件

jango框架:forms组件渲染标签、forms组件展示信息、forms组件校验补充、forms组件参数补充、forms组件源码剖析、modelform组件

时间:2023-01-04 21:47:21浏览次数:51  
标签:obj name form 补充 self 校验 forms 组件

目录

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

相关文章