Forms组件、勾子函数

Forms组件

前戏

前戏:编写用户登录功能并且校验数据返回提示信息(form表单)

写一个注册功能
1.获取用户名和密码 利用form表单提交数据
2.在后端判断用户名和密码是否符合一定的条件
	3.用户名不能是Jason
	4.密码不能为123

# 符合条件需要你将提示信息动态的展示到前端页面

前端

<form action="" method="post">
    <p>username:
        <input type="text" name="username">
        {# 行内标签 get请求为空 不占任何标签    post请求有值 就可以点到对应的数据    #}
        <span style="color: red">{{ data_dict.username }}</span>
    </p>
    <p>password:
        <input type="text" name="password">
        <span style="color: red">{{ data_dict.password }}</span>
    </p>
    <input type="submit" class="btn btn-info">
</form>

后端

def ab_form(request):
    # 不能使用ajax,那么它就是影响的整个页面
    data_dict = {'username': '', 'password': ''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if username == 'jason':
            data_dict['username'] = 'jason是不能使用的'
        if password == '123':
            data_dict['password'] = '密码不能设置这么简单的'
    return render(request, 'ab_form.html', locals())

image

form组件

1.数据校验
    	支持提前设置各种校验规则 之后自动校验
2.渲染页面
    	支持直接渲染获取用户数据的各种标签
3.展示信息
    	支持针对不同的校验失败展示不同的提示

form组件基本使用

1.form类型创建

首先需要导入模块:from django import forms
然后创建类

from django import forms

class MyForm(forms.Form):
    # 用户名最长8个字符,最短3个字符
    name = forms.CharField(max_length=8, min_length=3)
    # 用户年龄最大150,最小0岁
    age = forms.IntegerField(max_value=150, min_value=0)
    # 邮箱必须符合邮箱格式
    email = forms.EmailField()

2.校验数据

测试环境俩种方式

1.测试环境的准备 可以自己拷贝代码准备
2.其实在pycharm左下角已经帮你准备一个测试环境  "python console"
from app01 import views
# 1 将带校验的数据组织成字典的形式传入即可
form_obj = views.MyForm({'username':'jason','password':'123','email':'123'})

# 2 判断数据是否合法
注意该方法只有在所有的数据全部合法的情况下才会返回True
form_obj.is_valid()
False

# 3 查看所有校验通过的数据
form_obj.cleaned_data
{'username': 'jason', 'password': '123'}

# 4 查看所有不符合校验规则以及不符合的原因
form_obj.errors
{
  'email': ['Enter a valid email address.']
}

image
校验数据只校验类中出现的字段 多穿不影响 多穿的字段直接忽略

form_obj = views.MyForm({'username':'jason','password':'123','email':'123@qq.com','hobby':'study'})
form_obj.is_valid()
True

校验数据 默认情况下 类里面所有的字段都必须传值

form_obj = views.MyForm({'username':'jason','password':'123'})
form_obj.is_valid()

False

image

也就意味着校验数据的时候 默认情况下数据可以多传但是绝不可能少传

3.渲染标签功能(类中以外的所有标签都不会自动渲染 需要自己编写)

1.方式1(封装程度高 扩展性差)
{{ form_obj.as_p }}
{{ form_obj.as_table }}
{{ form_obj.as_ul }}

image
这种方法的缺点是封装程度太高了,什么都是人家渲染出来的,并且带了label和p标签,如果不想要呢,扩展性差
image
渲染成无序列表形式
image

2.方式2(封装程度低 扩展性好 编写困难)
{{ form_obj.name.label }}
{{ form_obj.name }}
{{ form_obj.age.label }}
{{ form_obj.age }}
{{ form_obj.email.label }}
{{ form_obj.email }}

image

3.方式3(推荐使用)
{% for form in form_obj %}
<p>{{ form.label }}{{ form }}</p>
{% endfor %}

image
只渲染类里写的字段,如果要使用按钮之类的需要自己写,类中意外的字段都不会自动渲染

4.展示提示信息

1.form表单如何取消浏览器自动添加的数据校验功能
<form action="" method="post" novalidate>
{#    novalidate不做任何校验#}
    {% for form in form_obj %}
    <p>{{ form.label }}{{ form }}</p>
    <input type="submit" value="提交">
{% endfor %}
</form>
2.form.errors生成的是列表的格式

image

3.错误信息展示
def func(request):
    # 产生一个空对象
    form_obj = MyForm()
    if request.method == 'POST':
        # 获取用户上传的数据,现在我们不需要用我们以前的那种笨拙的办法了(get)
        # request.POST它是一个dict,将它看作是一个字典
        # 产生了一个新的对象
        form_obj = MyForm(request.POST)
        # 判断一下我们传入的是否都是正确的
        if form_obj.is_valid():
            print(form_obj.cleaned_data)
    return render(request, 'func.html', locals())
<form action="" method="post" novalidate>
{#    novalidate不做任何校验#}
    {% for form in form_obj %}
    <p>
        {{ form.label }}{{ form }}
        <span style="color: red">{{ form.errors.0 }}</span>
    </p>

{% endfor %}
    <input type="submit" value="提交">
</form>

image

4.错误信息修改为中文
name = forms.CharField(max_length=8, min_length=3, label='用户名',
                           error_messages={
                               'max_length':'用户名最多只能是8个字符',
                               'min_length':'用户名最少只能是3个字符',
                               'required':'用户名不能为空'
                           }
                           )

image
可以以直接修改这里,将整个底层结构展示为中文,在settings.py里
image
image
image

5.form中重要的字段参数

max_length、min_length
max_value、min_value

label				字段注释
error_messages			错误提示
required			是否为空
widget				标签类型、标签属性
initial				默认值
validators			正则校验

钩子函数

需求:以上我们写的form组件中写一个注册功能,现在要求判断用户是否已经存在

提供自定义的校验方式
	局部钩子:校验单个字段
	全局钩子:校验多个字段

1.局部钩子:校验单个字段

class MyForm(forms.Form):
    '''属于第一层校验'''
    # 用户名最长8个字符,最短3个字符
    name = forms.CharField(max_length=8, min_length=3, label='用户名')
    pwd = forms.IntegerField(label='密码')
    confirm_pwd = forms.IntegerField(label='确认密码')
    # 用户年龄最大150,最小0岁
    age = forms.IntegerField()
    # 邮箱必须符合邮箱格式
    email = forms.EmailField()
    '''属于第二层校验,第一层校验通过以后才会执行这层校验'''
    # 1.校验用户名是否已经存在
    def clean_name(self):
        # 勾子函数会等上面的校验通过以后才会执行,相当于最后一层校验
        # 第二层校验的话cleaned_data里面肯定会有值,因为第一层校验已经通过了
        name = self.cleaned_data.get('name')
        res = models.User.objects.filter(name=name).first()
        if res:
            # 给前端一个消息,这个消息鬼属于name框,出错了提示会放在name框中
            return self.add_error('name', '用户名已存在')
        # 没有问题的话,记得拿了什么东西要返回回去,“把人家的东西勾来了,记得给放回去”
        return name
def func(request):
    # 产生一个空对象
    form_obj = MyForm()
    if request.method == 'POST':
        # 获取用户上传的数据,现在我们不需要用我们以前的那种笨拙的办法了(get)
        # request.POST它是一个dict,将它看作是一个字典
        # 产生了一个新的对象
        form_obj = MyForm(request.POST)
        # 判断一下我们传入的是否都是正确的
        if form_obj.is_valid():
            # 保存数据信息
            res = form_obj.cleaned_data
            # 要把确认密码移除调,它不属于我们数据库中,只是在校验中使用过
            res.pop('confirm_owd')
            models.User.objects.create(**res)
    return render(request, 'func.html', locals())

image

2.全局钩子:校验多个字段

# 2.校验俩次密码是否一致
# clean这个字段就是校验多个字段的,固定的
def clean(self):
    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

modelfrom组件

modelform是form的优化版本 使用更简单 功能更强大


class MyModelForm(forms.ModelForm):
    class Meta:
        # 写一下要争对哪一个表做校验
        model = models.User
        # 双下all代表着所有字段
        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

image

posted @ 2022-09-08 23:08  张张包~  阅读(64)  评论(0编辑  收藏  举报