46.Django07-2

1.form组件引入

写一个注册功能
获取用户名密码,利用form表单提交。
在后端判断用户名字和密码是否符合一些条件。
用户名不能含有 xx,密码不能少与三位。
如果符合要求将信息展示到前端页面中。
span行内标签字符有多大则块有多大,空字符则看不出。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
</head>
<body>
<form action="" method="post">
    <p>username:<input type="text" name="username">
        <span style="color: red">{{ back_dic.username }}</span>
    </p>

     <p>password:<input type="text" name="password">
         <span style="color: red">{{ back_dic.password }}</span>
     </p>
    <input type="submit" class="btn btn-info">
</form>
</body>
</html>
def ab_form(request):
    # 无论是get还是post能到字典get拿道空字段,post拿到输入的值
    back_dic = {'username': '', 'password': ''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        print(username, password)
        if 'xx' in username:
            back_dic['username'] = '名称不符合要求'
        if len(password) < 3:
            back_dic['password'] = '密码不能少于3位'

    return render(request, 'ab_form.html', locals())
form主键:
能够完成的以上三部:
1.获取用户的html代码前端代码,   渲染html代码
2.后端对获取数据进行校验         数据校验
3.数据不符要求在前端展示         展示错误提示信息
ps:
数据校验前端可有可无,后端必须有,全端页面的校验功能不完善。
能利用爬虫程序直接绕开全端页面向后端提交数据。

例:
购物网站
选中货物之后会计算价格发送给后端,价格的值可能被篡改,如果后端不做价格校验···

实际中获取到用户选择的商品的主键值,后端查询到的价格后在计算一此
如果前后端计算结果一致,完成支付,否则直接拒绝。

一般会进行前后端双重验证,保险、

2.forms组件

from django import forms
class MaForm(forms.Form):
    #  用户名与密码再少 3位 最大8位
    username = forms.CharField(min_length=3, max_length=8)
    password = forms.CharField(min_length=3, max_length=8)
    # 必须是邮箱格式 @xxx.xxx
    email = forms.EmailField()
2.1检验数据
测试环境的准备,可以自己拷贝代码,也可以使用pycharm的测试环境。
在pycharm Console中测试
from app01 import views
# 1. 将校验的数据组织成字段的格式传入   (request.POST 的对象也是字段,传入进行全部字段检验)
form_obj = views.MaForm({'username': 'kid', 'password': 123, 'email': '123@qq.com'})
# 2.判断数据是否合法 只有当数据全部合法的情况修啊才会放回True
form_obj.is_valid()
True
# 3.查看所有符合校验的数据
form_obj.cleaned_data
{'username': 'kid', 'password': '123', 'email': '123@qq.com'}
# 4. 查询所有不符合规则的数据籍不符原因
form_obj.errors
{}
# 5. 数据校验只检验类中出现的字段,多传不影响,多传的字段直接被忽略
form_obj = views.MaForm({'username': 'kid', 'password': 123, 'email': '123@qq.com', 'hobby': 'eat'})
form_obj.is_valid()
True
# 6. 检验数据 (默认情况下) 类里所有的字段都必须传值
form_obj = views.MaForm({'username': 'kid', 'password': 123})
form_obj.is_valid()
False
form_obj.errors
{'email': ['This field is required.']}


form_obj = views.MaForm({'username': 'kid', 'password': 123, 'email': '12qqom'})
form_obj.is_valid()
False
form_obj.cleaned_data
{'username': 'kid', 'password': '123'}
form_obj.errors
{'email': ['Enter a valid email address.']}
2.3渲染标签
forms组件只会渲染获取用户输入的便签(input select radio checkbox)
不会渲染提交按键
url(r'^index/', views.index)
def index(request):
    # 1.先生成一个空对象
    form_obj = MoForm()
    # 2.直接将空对象传入html页面
    return render(request, 'index.html', locals())
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>form组件获取输入</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <script src="JQuery.js"></script>
</head>
<body>
<form action="" method="post">
    <p>第一种渲染方式:代码书写极少,封装程度太高,不便于后续的拓展,一般情况下只在本地测试使用</p>
    {{ form_obj.as_p }}
    <br>
    <br>
    {{ form_obj.as_ul }}
    <br>
    <br>
    {{ form_obj.as_table}}
    <br>
    <br>
    <p>第二种渲染方式: 可扩展性强,但书写代码太多</p>
    {{ form_obj.username }}{{ form_obj.password }}
    <br>
    <br>
    <p>{{ form_obj.username.label }} :{{ form_obj.username }}</p>
    <p>{{ form_obj.password.label }} :{{ form_obj.password }}</p>
    <p>{{ form_obj.email.label }} :{{ form_obj.email }}</p>

</form>
</body>
</html>
label属性默认展示的字段首字母大写,也可以自己修改,直接在字段对象加label属性。

email = forms.EmailField(label='邮箱')

form_obj.username.label 获取属性的名称
form_obj.email.label    设置名称获取到 邮箱
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>form组件获取输入</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <script src="JQuery.js"></script>
</head>
<body>
<form action="" method="post">
    <p>第三种渲染方式:推荐实时。代码简单扩展性高</p>
    {% for form in form_obj %}
        <p>{{ form.label }}:{{ form }}</p>
    {% endfor %}
    <input type="submit" class="btn btn-info">
    
</form>

</body>
</html>

在这里插入图片描述

2.3渲染错误信息
浏览器会自动帮你检验数据,但是前端的检验能被篡改,
在form标签中添加 novalidate 属性,让浏览器不做校验。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>form组件获取输入</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    <script src="JQuery.js"></script>
</head>
<body>
<form action="" method="post" novalidate>
    <p>第三种渲染方式:推荐实时。代码简单扩展性高</p>
    {% for form in form_obj %}
        <p>{{ form.label }}:{{ form }}
        <span style="color: red">{{ form.errors.0 }}</span>
        </p>
{#        <span style="color: red">{{ form.errors }}</span>  会生ul便签,还有一串错误信息#}
{#        .0 不会生成ul便签 只拿错误信息的第一个 #}

    {% endfor %}
    <input type="submit" class="btn btn-info">

    
</form>

</body>
</html>
必备条件 get请求和post传给html的变量名必须一样,公用 ,第一个渲染方式。
forms组件当你数据不合法的情况下,或保存你上次的数据,让你基于之前的结果进行修改。
def index(request):
    # 1.先生成一个空对象
    form_obj = MoForm()
    if request.method == 'POST':
        """
        获取数据并检验数据
        1. 数据的获取
        2. 校验数据需要构造成字典的格式传入才行
        request.POST可以看成一个字典
        """
        # 3. 检验数据
        form_obj = MoForm(request.POST)
        # 4.判断数据是否合法
        if form_obj.is_valid():
            # 5.如果合法 存入数据
            pass
        else:
            # 错误信息展示到前端
            pass
    # 2.直接将空对象传入html页面
    return render(request, 'index.html', locals())
   # 前端错误信息是英文的,自定义中文错误信息。
    username = forms.CharField(min_length=3, max_length=8,
                               error_messages={
                                   'min_length': '用户名码少于3位数',
                                   'max_length': '用户名不能大于8位树数'
                               })
    password = forms.CharField(min_length=3, max_length=8,
                               error_messages={
                                   'min_length': '密码不少少于3位数',
                                   'max_length': '密码不能大于8位数'
                               })
    # 必须是邮箱格式 @xxx.xxx
    email = forms.EmailField(label='邮箱',
                             error_essages=
                             {
                                 'invalid': '邮箱格式不正确',
                                 'required': '邮箱不能为空'
                             }
                             )
2.4钩子函数(HOOK)
在特定的节点自动触发完成响应操作。
钩子函数在forms组件中类似于第二道关卡,能够设置自定义校验规则。
在forms组件中有两类钩子
1. 局部钩子
当你需要给某个字段增加校验规则的时候可以使用
2. 全局钩子
当你需要给某多字段增加校验规则的时候可以使用
1.校验用户名中不能含有666      只校验username 字段 使用局部钩子
2.检验密码和确认密码是否一致    校验password confirm 两个字段全局钩子


# 在类里面书写方法。
from django import forms
class MoForm(forms.Form):
    #  用户名与密码再少 3位 最大8位
    username = forms.CharField(min_length=3, max_length=8,
                               error_messages={
                                   'min_length': '用户名码少于3位数',
                                   'max_length': '用户名不能大于8位树数',
                                   'required': '用户名不能为空'

                               })
    password = forms.CharField(min_length=3, max_length=8,
                               error_messages={
                                   'min_length': '密码不少少于3位数',
                                   'max_length': '密码不能大于8位数',
                                   'required': '密码不能为空'
                               })
    confirm = forms.CharField(min_length=3, max_length=8,
                               error_messages={
                                   'min_length': '密码不少少于3位数',
                                   'max_length': '密码不能大于8位数',
                                    'required': '密码不能为空'
                               })
    # 必须是邮箱格式 @xxx.xxx
    email = forms.EmailField(label='邮箱',
                             error_messages=
                             {
                                 'invalid': '邮箱格式不正确',
                                 'required': '邮箱不能为空'
                             }
                             )
    # 局部 钩子函数,自动生成对应字典的钩子函数名。
    def clean_username(self):
        username = self.cleaned_data.get('username')
        if '666' in username:
            # 提示前端展示错误
            self.add_error('username', '不能含有666')
        # 将钩子函数勾出来的来的数据在放放回回去
        return username

    # 全局 钩子函数
    def clean(self):
        password = self.cleaned_data.get('password')
        confirm = self.cleaned_data.get('confirm')
        if not confirm == password:
            self.add_error('confirm', '两个密码不一致')
        # 将钩子够的函数全部返回去
        return self.cleaned_data
2.5其他参数
1.针对不同的类型input修改
	text     普通文本(默认)  
	password 密文
	date     日期
	···
添加参数 
widget = forms.widget.TextTnput() 普通文本
widget = forms.widget.PasswordTnput() 密文
widget = forms.widget.EmailTnput() 密文

2. 字段设置样式 多个属性,空格隔开
widget = forms.widget.TextTnput(attrs={'class':'form-control c1 c2', 'value':'kid'}) 
label 字段名
error_messages 自定义报错信息
initial 默认值 initial = 'kid' 框内默认展示kid
required 控制字段是否必填 required=False 可以不填
···
from django import forms
class MoForm(forms.Form):
    #  用户名与密码再少 3位 最大8位
    username = forms.CharField(min_length=3, max_length=8,
                               initial='kid',
    error_messages={
                                   'min_length': '用户名码少于3位数',
                                   'max_length': '用户名不能大于8位树数',
                                   'required': '用户名不能为空'
                               },
                               widget=forms.widgets.TextInput(
                                   # 写属性  'value': '两次密码必须一致' 同   initial的效果框内默认值
                               attrs={'class': 'form-control c1 c2'}
                               )
                               )

    password = forms.CharField(min_length=3, max_length=8,
                               error_messages={
                                   'min_length': '密码不少少于3位数',
                                   'max_length': '密码不能大于8位数',
                                   'required': '密码不能为空'
                               },
                               widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
                               )

    confirm = forms.CharField(min_length=3, max_length=8,
                               error_messages={
                                   'min_length': '密码不少少于3位数',
                                   'max_length': '密码不能大于8位数',
                                    'required': '密码不能为空'
                               },
                              widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'} )
                              )

    # radio
    gender = forms.ChoiceField(
        choices=((1, "男"), (2, "女"), (3, "保密")),
        label="性别",
        initial=3,
        widget=forms.widgets.RadioSelect()
    )
    # select
    hobby1 = forms.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=3,
        widget=forms.widgets.Select()

    )
    # 多选
    hobby2 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )
    # 单选的 checkbox
    keep = forms.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )
    # 多选的checkbox
    hobby3 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )

    # 必须是邮箱格式 @xxx.xxx
    email = forms.EmailField(label='邮箱',
                             error_messages=
                             { 'invalid': '邮箱格式不正确',
                                'required': '邮箱不能为空'})

    # 将from 丢上去
    from django.core.validators import RegexValidator
    phone = forms.CharField(
        # 支持正则校验
        validators =
        [RegexValidator(r'^[0-9]+$', '请输入数字'),
         RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
    )

    # 局部 钩子函数,自动生成对应字典的钩子函数名。
    def clean_username(self):
        username = self.cleaned_data.get('username')
        if '666' in username:
            # 提示前端展示错误
            self.add_error('username', '不能含有666')
        # 将钩子函数勾出来的来的数据在放放回回去
        return username

    # 全局 钩子函数
    def clean(self):
        password = self.cleaned_data.get('password')
        confirm = self.cleaned_data.get('confirm')
        if not confirm == password:
            self.add_error('confirm', '两个密码不一致')
        # 将钩子够的函数全部返回去
        return self.cleaned_data

3.forms源码

切入点在form_obj.is_valid()

    def is_valid(self):
        """
        Returns True if the form has no errors. Otherwise, False. If errors are
        being ignored, returns False.
        """
        return self.is_bound and not self.errors
		# 如果is_avlid要返回True 那么self.is_bound要为True  self.errors 为False
    # 只要传的值不为空就是 True
    self.is_bound = data is not None or files is not None  
    
    
  
    @property
    def errors(self):
        "Returns an ErrorDict for the data provided for the form"
        # self._errors = None 默认就是	None 百分百走if
        if self._errors is None:
            self.full_clean()
        return self._errors

    # forms组件所有功能都出自于该方法
    def full_clean(self):
		···
        self._clean_fields()  # 检验字典 + 局部钩子
        self._clean_form()    # 全局钩子
        self._post_clean()    # 用不到
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值