markdownpad2 html渲染组件出错_Day68 Django forms组件

目录

  • forms组件
  • forms组件类书写
  • forms组件如何校验数据
  • forms组件如何渲染标签
  • forms组件展示错误信息
  • forms组件钩子函数(HOOK)
  • forms组件常见参数
  • forms组件源码

1、forms组件

小示例:
写一个注册功能:
利用form表单提交数据,获取用户名密码,在后端判断用户名密码是否符合条件:用户名不能包含abc字符串,密码不能少于6位数。

views.py文件:

from django.shortcuts import render

# Create your views here.
def ab_form(request):
    back_dic = {'username':'','password':''}
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')
        if 'abc' in username:
            back_dic['username'] = '用户名不能包含字符串abc'
        if len(password)<6:
            back_dic['password'] = '密码必须为6位数'
    # back_dic字典值默认是空,当用户输入用户名密码并提交时,就发起了post请求,back_dic通过校验如果不符合要求就会传值
    return render(request,'ab_form.html',locals())

html页面:

<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="password" name="password">
        <span style="color: red">{{ back_dic.password }}</span>
    </p>
    <input type="submit" class="btn btn-info" value="submit">
</form>
</body>

1968d98e0aabedb7c3fb8c0cb8dd8732.png

以上我们就手动完成了需求:
1、书写前端获取用户数据的HTML代码
2、后端对用户数据进行校验
3、对不符合要求的数据进行前端提示

实际上以上功能form组件都能完成(渲染代码、校验数据、前端展示提示)。

应用场景:例如博客园的注册页面

21613892c0f2da366d20e4cc3fe3f277.png

数据校验前端可有可无,但是后端必须要有!因为前端的校验你可以直接修改,或者利用爬虫程序绕过前端页面直接朝后端提交数据。

2、forms组件类书写

views.py文件中:

from django import forms
class MyForm(forms.Form):
    # username,password这两个字段最少3位数,最大8位数
    username = forms.CharField(min_length=3,max_length=8)
    password = forms.CharField(min_length=3,max_length=8)
    # email字段必须符合邮箱格式,xx@xx.com
    email = forms.EmailField()

3、forms组件如何校验数据

测试环境的准备除了我们之前用的tests.py,在pycharm里面已经给我们提供了一个Django的测试环境:点击Python Console:

ea2570644255543d09b58a72e4a21092.png

校验步骤:
1、将要校验的数据组织成形式传入
2、判断数据是否合法,is_valid()方法用来校验我们传入的字典数据是否合法,该方法只有在所有的数据全部合法的情况下才会返回True
3、cleaned_data拿到所有符合条件的数据;
4、errors拿到所有不符合校验规则的数据以及不符合规则的原因,以键值对的形式展现,并且值是以列表的形式,因为一个字段有可能会不符合多个规则。

83933b2e20a31d0ab33c2f17b2c4cfcc.png


如果我再多传入一个hobby键:
form_obj = views.MyForm({'username':'jack','password':'12','email':'123','hobby':'study'})那么hobby是不会被校验的,只会找MyForm类里面书写的字段去做校验,而hobby不会被放到cleaned_data也不会被放到errors中。
默认情况下,类里面的所有字段都必须传值。如果少传了一个键,少传的那个字段会被放到errors中:
form_obj = views.MyForm({'username':'jack','password':'123'})
form_obj.errors
{'email': ['This field is required.']}
form_obj.cleaned_data
{'username': 'jack', 'password': '123'}

4、forms组件如何渲染标签

结合form组件获取用户注册的用户名密码邮箱,有了form组件之后所有获取用户输入的标签都不需要自己写了。form组件不会帮你渲染提交按钮,要自己添加。

views.py文件:

from django import forms
class MyForm(forms.Form):
    # username,password这两个字段最少3位数,最大8位数
    username = forms.CharField(min_length=3,max_length=8,label='用户名')
    password = forms.CharField(min_length=3,max_length=8,label='密码')
    # email字段必须符合邮箱格式,xx@xx.com
    email = forms.EmailField(label='邮箱')

def index(request):
    # 1、先产生一个空对象
    form_obj = MyForm()
    # 2、直接将该空对象传递给HTML页面
    return render(request,'index.html',locals())

前端index.html页面(前端对生成的空对象做操作):
label属性默认展示的是类中字段首字母大写的形式,也可以修改:通过给字段加label属性。

<body>
<form action="" method="post">
    <p>第一种form表单渲染方式:</p>
    <p>代码书写极少,封装程度太高,不利于后续的扩展,一般只在本地测试使用</p>
    <p>as_p</p>
    {{ form_obj.as_p }}
    <p>as_ul</p>
    {{ form_obj.as_ul }}
    <p>as_table</p>
    {{ form_obj.as_table }}

    <p>第二种form表单渲染方式:</p>
    <p>可扩展性强,但是需要书写的代码太多,一般不用</p>
    <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>

    <p>第三种form表单渲染方式:</p>
    <p>代码书写简单,扩展性高,推荐使用</p>
    {% for form in form_obj %}
       <p> {{ form.label }} :{{ form }} </p>
    {% endfor %}

</form>
</body>

bebf8eb9b3595f7deff2e8547591b7b4.png

3e402394af896e3dd9475728d466f903.png

5、forms组件展示错误信息

浏览器会自动帮你做校验(如下图的提示信息),但是前端的校验还是不安全,我们可以给form表单加个参数取消前端浏览器自动校验功能:<form action="" method="post" novalidate>

cec1aa192316b58aee512059303ae97c.png

form表单展示错误信息需要注意:
1、get请求和post请求传给页面的对象变量名必须一致form_obj
2、当你的数据不合法时,form组件会保存你输入的数据,让你基于上次的输入数据进行修改,更加人性化

views.py文件

from django import forms
class MyForm(forms.Form):
    # username,password这两个字段最少3位数,最大8位数
    username = forms.CharField(min_length=3,max_length=8,label='用户名',
                               error_messages={
                                   'min_length':'用户名最少3位',
                                   'max_length':'用户名最多8位',
                                   'required':'用户名不能为空'
                               })
    password = forms.CharField(min_length=3,max_length=8,label='密码',
                               error_messages={
                                   'min_length': '密码最少3位',
                                   'max_length': '密码最多8位',
                                   'required': '密码不能为空'
                               })
    # email字段必须符合邮箱格式,xx@xx.com
    email = forms.EmailField(label='邮箱',
                            error_messages={
                             'invalid':'邮箱格式不正确',
                             'required': '邮箱不能为空'
                            })


def index(request):
    # 1、先产生一个空对象
    form_obj = MyForm()
    if request.method == 'POST':
        # 3、校验数据
        form_obj = MyForm(request.POST)
        # 4、判断数据是否合法
        if form_obj.is_valid():
            # 5、如果合法,操作数据库存储数据
            return HttpResponse('OK')
        # 5、如果不合法,将错误信息展示到前端

    # 2、直接将该空对象传递给HTML页面
    return render(request,'index.html',locals())

index.html页面:

<body>
<form action="" method="post" novalidate>
    {% for form in form_obj %}
        <p> {{ form.label }} :{{ form }}
{#          form.errors.0这后面加了一个.0表示只拿列表第一个错误信息,就不会自动帮你生成ul标签 #}
            <span style="color:red">{{ form.errors.0 }}</span>
        </p>
    {% endfor %}
    <button>提交</button>
</form>
</body>

cb2bbfc0fb11eb459346ac6b721d8884.png

在给字段添加了error_messages参数之后,错误提示就变成自己输入的了(自定义)。

af46d00d609067d3051eea0317573fbd.png

6、forms组件钩子函数

钩子函数:在特定的节点自动触发完成响应操作
在form组件中有两类钩子
1、局部钩子
当你需要给某个字段增加校验规则的时候可以使用,在后端校验的基础上进行二次校验。
2、全局钩子
当你需要给多个字段增加校验规则的时候可以使用。

实际案例:
1、校验用户名中不能包含666(只需要校验用户名,可以用局部钩子)
2、校验密码和确认密码是否一致(校验密码字段和确认密码字段,需要用全部钩子)

views.py文件做如下修改:

from django import forms
class MyForm(forms.Form):
    # username,password这两个字段最少3位数,最大8位数
    username = forms.CharField(min_length=3,max_length=8,label='用户名',
                               error_messages={
                                   'min_length':'用户名最少3位',
                                   'max_length':'用户名最多8位',
                                   'required':'用户名不能为空'
                               })
    password = forms.CharField(min_length=3,max_length=8,label='密码',
                               error_messages={
                                   'min_length': '密码最少3位',
                                   'max_length': '密码最多8位',
                                   'required': '密码不能为空'
                               })
    confirm_password = forms.CharField(min_length=3,max_length=8,label='确认密码',
                               error_messages={
                                   'min_length': '密码最少3位',
                                   'max_length': '密码最多8位',
                                   'required': '密码不能为空'
                               })
    # email字段必须符合邮箱格式,xx@xx.com
    email = forms.EmailField(label='邮箱',
                            error_messages={
                             'invalid':'邮箱格式不正确',
                             'required': '邮箱不能为空'
                            })
    # 局部钩子
    def clean_username(self):
        # 获取用户名
        username = self.cleaned_data.get('username')
        if '666' in username:
            # 提示前端展示错误信息
            # 提示方式1:
            self.add_error('username','用户名不能包含666')
            # 提示方式2(繁琐,一般不用):
            # raise ValidationError('用户名不能包含666.')
        # 将钩子函数钩取出来的数据再放回去
        return username

    # 全局钩子
    def clean(self):
        # 获取两个密码字段
        password = self.cleaned_data.get('password')
        confirm_password = self.cleaned_data.get('confirm_password')
        if not confirm_password == password:
            self.add_error('confirm_password','两次密码不一致')
        # 校验后将全局钩子钩出来的数据再放回去
        return self.cleaned_data

5e8d28c2ea2fe405014dca3c9d5471db.png

7、forms组件常见参数

label='用户名',设置字段名
error_messages={'min_length': '密码最少3位',},自定义报错信息
initial='jack',默认值
required=False,设置成必填字段
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'}),调整样式(多个属性值用空格隔开即可)
from django.core.validators import RegexValidator
class MyForm(Form):
user = fields.CharField(validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
),支持字段写正则表达式,可以写多个正则一一匹配

其他类型渲染:
radiocheckboxselect
Django Form表单组件 - JasonJi - 博客园​www.cnblogs.com
class LoginForm(forms.Form):
    ...
    hobby = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.CheckboxSelectMultiple()
    )
keep = forms.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )
hobby = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )

针对字段的校验方式:
1、最简单的max_length,min_length
2、正则validator
3、钩子函数

8、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_valid要返回true的话,那么self.is_bound要为true,self.errors要为false
#         self.is_bound = data is not None or files is not None
#    所以只要你传数据了,那么self.is_bound就是true

    @property
    def errors(self):
        "Returns an ErrorDict for the data provided for the form"
        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()
forms组件源码​www.bilibili.com
b1b5a0e3757d2c3451c8d7e1a9cf4e4f.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值