Django 与forms组件
1.应用
- 
一般应用于前端的登入、注册界面, 对用户输入的字段进行校验, 快速的判断用户输入的内容是否合法, 并返回信息
 
2.为何不在前端直接使用JS进行校验
- 
前端的校验可以没有, 但后端的校验必须要有
 - 
因为前端的校验弱不禁风, 有很多种方式可以伪装成浏览器发送请求传递数据
 - 
或者通过爬虫程序绕过前端页面直接朝后端提交数据
 
二.forms组件的基本使用(步骤)
- 
导入forms组件
 - 
定义一个类, 并继承Form
 - 
在类中书写要校验的字段, 字段的属性就是要校验的规则
 - 
实例化得到一个Form对象, 把要校验的数据传入
 - 
调用
[form对象].is_valid( )方法进行校验, 校验通过返回True - 
校验通过调用
[form对象].cleaned_data获得校验后的数据 - 
校验失败调用
[form对象].errors获得错误信息 
三.forms组件基本使用示例
简单的用户注册界面示例
1.常用字段属性
| 属性 | 释义 | 
|---|---|
| min_length | 最小长度 | 
| max_length | 最大长度 | 
| require | 该字段必须得填 | 
| label | 该字段的标签 | 
2.组件文件 form.py
- 
建议在应用文件夹下创建一个专门存放forms组件的文件 (不创建直接写在views.py中也可以)
 - 
导入组件并创建类
 
from django import forms
class RegisterForm(forms.Form):
    # 校验name字段,最大长度为8,最短为3,下面的字段类似
    name = forms.CharField(max_length=8, min_length=3, lable='用户名')
    password = forms.CharField(max_length=10, min_length=4, lable='密码')
    re_password = forms.CharField(max_length=10, min_length=4, lable='确认密码')
    email = forms.EmailField(lable='邮箱')
3.视图层 views.py 文件
- 
实例forms对象, 使用对方法进行校验
 
from app01.myform import RegisterForm
def register(request):
    if request.method == 'POST':
        # 实例得到form对象,将需要校验的数据传入(数据可以是前端传过来的数据,也可以是自己后端已有的数据)
        # dic = {'name':'shawn','password':'1111','re_password':'1111','email':'123@qq.com'}
        # form_data = RegisterForm(dic)  # 示例:直接将已有的数据传入
        form_data = RegisterForm(request.POST)  # 将前端post请求的数据传入
        # 进行校验 is_valid()
        if form_data.is_valid():
            print('校验成功')
            # 获得校验成功的数据 cleaned_data
            print(form_data.cleaned_data)
            return HttpResponse('校验成功')
        else:
            print('检验失败')
            # 获得检验失败的错误提示 errors
            print(form_data.errors)
    # forms组件可以自动生成HTML代码,因此可以直接在页面上进行显示
    form_data = RegisterForm()  # 先产生form空对象,再将其传给前端
    return render(request, 're_form.html', {'form': form_data})
ps :
cleaned_data属性必须是经过is_valid( )校验之后才产生的, 在校验之前使用会报错 : 属性不存在
4.路由层 urls.py 文件
re_path('^re_form/', views.register)
5.模板层 re_form.html 文件
<div class="container">
    <div class="row">
        <div class="col-md-4">
            <div class="panel panel-info">
                <div class="panel-heading">注册页面</div>
                <div class="panel-body">
                    <form action="" method="post">
                        <p>用户名:{{ form.name }}</p>
                        <p>密码:{{ form.password }}</p>
                        <p>确认密码:{{ form.re_password }}</p>
                        <p>邮箱:{{ form.email }}</p>
                        <br>
                        <input type="submit" class="btn btn-block btn-success" value="注册">
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
6.测试效果
- 
检验失败展示
 
- 
检验成功展示
 
四.forms组件之渲染标签方式
1.自动渲染方式一
- 
就是上面示例中的写法
 - 
可扩展性很强, 但是需要书写的代码太多
 
<form action="" method="post">
    <p>用户名:{{ form.name }}</p>
    <p>密码:{{ form.password }}</p>
    <p>确认密码:{{ form.re_password }}</p>
    <p>邮箱:{{ form.email }}</p>
    <br>
    <input type="submit" class="btn btn-block btn-success" value="注册">
</form>
- 
也可以使用label标签替代前缀(''用户名''、''密码''等等)
 
<form action="" method="post">
    <p>{{ form.name.label }}:{{ form.name }}</p>
    <p>{{ form.password.label }}:{{ form.password }}</p>
    <p>{{ form.re_password.label }}:{{ form.re_password }}</p>
    <p>{{ form.email.label }}:{{ form.email }}</p>
    <br>
    <input type="submit" class="btn btn-block btn-success" value="注册">
</form>
2.自动渲染方式二(常用方式)
- 
使用for循环
 - 
代码书写简单, 并且扩展性也高 (推荐使用)
 
<form action="" method="post" novalidate>
    {% for foo in form %}
        <div class="form-group">
            {# 循环取出 name,password,re_password,email #}
            <p>{{ foo.label }}:{{ foo }}</p>
        </div>
    {% endfor %}
    <input type="submit" class="btn btn-block btn-success" value="注册">
</form>
3.自动渲染方式三(不常用)
- 
代码书写极少, 封装程度太高, 不便于后续的扩展, 一般情况下只在本地测试使用
 
<form action="" method="post" novalidate>
    {{ form.as_p }}       {# 与上两种显示方式相同 #}
    {{ form.as_ul }}      {# 前面带点 #}
    {{ form.as_table }}   {# 在一行显示 #}
    <input type="submit" class="btn btn-block btn-success" value="注册">
</form>
五.forms组件之渲染错误信息
1.字段参数(举例)
- 
required : 是否允许为空,默认False
 - 
error_messages : 自定义错误信息
 - 
widget: 使用HTML插件
- 
TextInput
 - 
PasswordInput
 
 - 
 
2.代码演示
- 
myform.py 文件
 
from django import forms
from django.forms import widgets
class RegisterForm(forms.Form):
    # 校验name字段,最大长度为8,最短为3,下面的字段类似
    name = forms.CharField(max_length=8, min_length=3, label='用户名',
                           # 自定义错误信息
                           error_messages={
                               'min_length': '用户名最少3位!',
                               'max_length': '用户账户最大8位',
                               'required': '用户名不能为空!',
                           },
                           # 添加一个form-control类
                           widget=widgets.TextInput(attrs={'class':'form-control'}))
    password = forms.CharField(max_length=10, min_length=4, label='密码',
                               error_messages={
                                   'min_length': '密码最少4位!',
                                   'max_length': '密码最大10位',
                                   'required': '密码不能为空!',
                               },
                               widget=widgets.PasswordInput(attrs={'class':'form-control'}))
    re_password = forms.CharField(max_length=10, min_length=4, label='确认密码',
                                  error_messages={
                                      'min_length': '密码最少4位!',
                                      'max_length': '密码最大10位',
                                      'required': '密码不能为空!',
                                  },
                                  widget=widgets.PasswordInput(attrs={'class':'form-control'}))
    email = forms.EmailField(label='邮箱',
                             error_messages={
                                 'invalid': '邮箱格式不正确',
                                 'required': '邮箱不能为空',
                             },
                             widget=widgets.TextInput(attrs={'class':'form-control'}))
- 
views.py 文件
 
from app01.myform import RegisterForm
def register(request):
    if request.method == 'POST':
        form_data = RegisterForm(request.POST)  # 将前端post请求的数据传入
        if form_data.is_valid():
            print(form_data.cleaned_data)
            return HttpResponse('校验成功')
        else:
            # 将带有错误信息的form对象返回前端页面
            return render(request, 're_form.html', {'form': form_data})
    form_data = RegisterForm()  # 将form对象传给前端
    return render(request, 're_form.html', {'form': form_data})
- 
re_form.html 文件
 
<form action="" method="post" novalidate>
    {% for foo in form %}
        {# 在后方设置一个span标签用来放错误提示 #}
        <p>{{ foo.label }}:{{ foo }}
            <span style="color: red">{{ foo.errors.0 }}</span>
        </p>
    {% endfor %}
    <input type="submit" class="btn btn-block btn-success" value="注册">
</form>
ps :
<form action="" method="post" novalidate>: form 表单标签内的novalidate表示前端不进行校验
3.效果展示
六.forms组件之全局钩子, 局部钩子
1.钩子函数
- 
全局和局部钩子都是定义在forms组件之内的函数
 - 
钩子函数类似于校验的第二道关卡, 能够让我们自定义校验规则
 
2.两种钩子函数
- 
局部钩子 : 用于给单个字段增加校验规则
 - 
全局钩子 : 用于给多个字段增加校验规则
 
3.两种钩子函数的书写方式
- 
局部钩子
 
def clean_字段名(self):
    字段值 = self.cleaned_data.get('字段名')
    [判断逻辑代码]
    [不通过抛出 ValidationError 异常]
    [通过则返回该字段值]
- 
全局钩子
 
def clean(self):
    字段值1 = self.cleaned_data.get('字段1')
    字段值2 = self.cleaned_data.get('字段2')
    [判断逻辑代码]
    [不通过抛出 ValidationError 异常]
    [通过则 return self.cleaned_data]
4.钩子示例
- 
需求一 : 校验用户名不能有敏感字眼
 - 
需求二 : 校验两次输入的密码需一致
 
myform.py 新增钩子函数
# 局部钩子 def clean_name(self): name = self.cleaned_data.get('name') for i in ['爱德华','sb']: if i in name: raise ValidationError(f'用户名中包含敏感词汇:"{i}"') else: return name  # 全局钩子 def clean(self): password = self.cleaned_data.get('password') re_password = self.cleaned_data.get('re_password') if password == re_password: return self.cleaned_data else: raise ValidationError('两次密码不一致')
views.py 文件
from app01.myform import RegisterForm   def register(request): if request.method == 'POST': form_data = RegisterForm(request.POST) # 将前端post请求的数据传入  if form_data.is_valid(): return HttpResponse('校验成功') else: # 获取到 ValidationError 中的 error 信息传给前端 error = form_data.errors.get('__all__') return render(request, 're_form.html', {'form': form_data,'error':error})  form_data = RegisterForm() # 将form空对象传给前端 return render(request, 're_form.html', {'form': form_data})
re_form.html 文件
<form action="" method="post" novalidate> {% for foo in form %} <p>{{ foo.label }}:{{ foo }} <span style="color: red; display:inline-block">{{ foo.errors.0 }}</span> </p> {% endfor %}  <input type="submit" class="btn btn-block btn-success" value="注册"> {# 判断错误信息是否为None,是None就不渲染error #} {% if error is None %} <span style="color: red; display:inline-block"></span> {% else %} <span style="color: red; display:inline-block">{{ error }}</span> {% endif %} </form>
需求一演示 :
需求二演示 :
七.error错误提示为何是ul标签分析
- 
上面我们在 views.py 文件中写到的,教研室表打印错误提示信息
 
else: print('检验失败') # 获得检验失败的错误提示 errors print(form_data.errors)
- 
查看打印结果 :
 
为什么是一个
ul标签格式, 一定是重写了__str__方法
- 
我们导入 ErrorDict 来查看内部源码
 
from django.forms.utils import ErrorDict
发现其内部重写了
__str__方法, 返回的是as_ul方法, 该方法内部就是定义了html的格式并返回并且还有一些其他的方法 : 比如 json 格式, data 数据, text 格式等等
而返回
as_ul方法则是为了方便渲染模板
八.常用字段及插件
1. 初始值 : initial
username = forms.CharField( min_length=8, label="用户名", initial="shawn" # 设置默认值 )
2. 自定义错误提示 : error_massages
username = forms.CharField( min_length=8, label="用户名", initial="shawn", error_messages={ "required": "不能为空", "invalid": "格式错误", "min_length": "用户名最短8位" } )
3. 密码框 : password
# 设置render_value在输入错误的时候, 保留输入的内容value值 pwd = forms.CharField( min_length=4, label="密码", widget=forms.widgets.PasswordInput(attrs={'class': 'a1'}, render_value=True) )
4. 反选radio
gender = forms.fields.ChoiceField( choices=((1, "男"), (2, "女"), (3, "未知")), label="性别", initial=3, widget=forms.widgets.RadioSelect() )
5. 单选checkbox
keep = forms.ChoiceField( label="是否记住密码", initial="checked", widget=forms.widgets.CheckboxInput() )
6. 多选checkbox
Copyhobbies1 = forms.MultipleChoiceField( choices=((1, "read"), (2, "run"), (3, "play"),), label="爱好", initial=[1, 3], widget=forms.widgets.CheckboxSelectMultiple() )
7. 单选Select
Copyeducation = forms.ChoiceField( choices=((1, "高中"), (2, "中专"), (3, "大专"), (4, "本科"), (5, "研究生"), (6, "硕士")), label="学历", initial=3, widget=forms.widgets.Select(attrs={'class': 'form-control'}) )
8. 多选Select
Copyhobbies2 = forms.MultipleChoiceField(
    choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
    initial=[1, 2],
    widget=forms.widgets.SelectMultiple(attrs={'class': 'form-control'})
)
9.更多插件(了解)
| 插件名称 | 对应input | 
|---|---|
| TextInput | input type="text" | 
| PasswordInput | input type="password" | 
| HiddenInput | input type="hidden" | 
| NumberInput | input type="number" | 
| EmailInput | input type="email" | 
| URLInput | input type="url" | 
| Textarea | textarea | 
| DateInput | input type="data" | 
| DateTimeInput | input type="datetime" | 
| TimeInput | 只获取时分秒 | 
| CheckboxInput | input type="checkbox" | 
| CheckboxSelectMultiple | 多选按钮 | 
| Select | select框 | 
| NullBooleanSelect | select框 三个选项 0 1 null | 
| SelectMultiple | 可多选的select框 | 
| RadioSelect | input type="radion" | 
| FileInput | 可以查看当前目录下的所有文件。作用不大 | 
版权声明:
                                    
作者:淘小欣                                    
链接:https://blog.taoxiaoxin.club/165.html
                                    
来源:淘小欣的博客                                    
文章版权归作者所有,未经允许请勿转载。
                                
                







共有 0 条评论