• Django Form组件


    Form组件的简单使用

    创建models类

    以员工注册为例,创建一个表示员工表的类
    models.py

    from django.db import models
    
    # Create your models here.
    
    
    class Emp(models.Model):
        name = models.CharField(max_length=32)
        age = models.IntegerField()
        salary = models.DecimalField(max_digits=8, decimal_places=2)
    
    

    ## 自定义Form类 在app1下面新建一个py文件 myForm.py(myForm是自己起的名字)
    from django import forms
    
    
    class EmpForm(forms.Form):
        # 这里定义的字段和models里面的Emp表的字段必须一一对应
        # label的值为input对应的label标签显示的内容
        # error_message:验证未通过时显示的信息
        name = forms.CharField(min_length=5, label='姓名', error_messages={
            # 键:字段约束,required是form组件自动加的
            # 值:验证未通过时显示的错误信息
            'required': '姓名不能为空',
            'min_length': '姓名至少为5位',
        })  # 定制约束条件
        age = forms.IntegerField(label='年龄')
        salary = forms.DecimalField(max_digits=5, decimal_places=2, label='工资')
    
    

    ## 在视图函数里生成form对象并将form对象传给前端 views.py ```python from django.shortcuts import render, HttpResponse, redirect from app1.myForm import EmpForm from app1 import models # Create your views here.

    1. 自己写html页面

    def login(request):

    if request.method == 'POST':

    pass

    else:

    return render(request, 'login.html')

    2. 用form自动生成html页面

    def login(request):
    if request.method == 'POST':
    # 把request.POST作为参数传进去
    form = EmpForm(request.POST)
    # 验证数据
    if form.is_valid():
    # 打印验证过的数据(可以写进数据库里)
    print('form.cleaned_data:', form.cleaned_data)
    models.Emp.objects.create(**form.cleaned_data)
    else:
    # 打印错误信息
    print('form.errors:', form.errors)
    return render(request, 'login.html', {'form': form})
    else:
    form = EmpForm() # 实例化一个EmpForm对象
    # 把form传给前端页面
    return render(request, 'login.html', {'form': form})

    
    <br>
    ## 在前端页面里用form对象生成html标签
    login.html
    ```html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <h1>员工注册</h1>
    
    {# 1. 自己写的html页面 #}
    {#<form action="" method="post">#}
    {#    {% csrf_token %}#}
    {#    <p>姓名:<input type="text" name="name"></p>#}
    {#    <p>年龄:<input type="text" name="age"></p>#}
    {#    <p>工资:<input type="text" name="salary"></p>#}
    {#    <input type="submit">#}
    {#</form>#}
    
    
    {# 2. aas_p: 一次展示所有字段 #}
    {#<form action="" method="post">#}
        {#  Return this form rendered as HTML <p>s.  #}
        {#  注意会把intfield渲染成type=number  #}
    {#    {{ form.as_p }}#}
        {#  注意这里不会渲染submit标签,需要自己写  #}
    {#    <input type="submit">#}
    {#</form>#}
    
    
    {# 3. 手动获取form对象的字段 #}
    {#<form action="" method="post">#}
    {#    <div>#}
            {# form.name是一个form表单下输入姓名的的标签 #}
            {# form.name.name是这个标签的值 #}
    {#        <label for="id_{{ form.name.name }}">姓名</label>#}
            {# form组件会自动给input标签加上一个id,id名为id_字段名 #}
    {#        {{ form.name }} <span>{{ form.name.errors.0 }}</span>#}
    {#    </div>#}
    {#    <div>#}
    {#        <label for="id_{{ form.age.name }}">年龄</label>#}
    {#        {{ form.age }} <span>{{ form.age.errors.0 }}</span>#}
    {#    </div>#}
    {#    <div>#}
    {#        <label for="id_{{ form.salary.name }}">工资</label>#}
    {#        {{ form.salary }} <span>{{ form.salary.errors.0 }}</span>#}
    {#    </div>#}
    {#    <input type="submit">#}
    {#</form>#}
    
    
    {# 4. for循环获取form对象的字段 #}
    <form action="" method="post" novalidate>
        {% csrf_token %}
        {% for field in form %}
            <div>
                <label for="id_{{ field.name }}">{{ field.label }}</label>
                {# field.errors是一个列表,一般只显示第一个就可以了,解决了再显示下一个 #}
                {{ field }} <span>{{ field.errors.0 }}</span>
            </div>
        {% endfor %}
        <input type="submit">
    </form>
    {# 注意:用这种方式生成的input标签会自动加上required属性,也就是不能为空 #}
    {# 为空时提交不了,浏览器会显示必须填写此字段 #}
    {# 如果要去掉这个,在form里加上novalidate,告诉浏览器不用验证直接提交(正常期间狂不用加) #}
    
    {# 提交验证未通过时,form组件会保留用户输入的信息 #}
    
    </body>
    </html>
    
    

    ## 小结 ### 什么是Form组件? Form组件就是用一个类来表示form表单,类的属性对应form表单里面的input标签,注意不包括submit按钮 ### Form组件有哪些作用? - 页面初始化,生成HTML标签 - 校验用户数据(显示错误信息) - HTML Form提交保留上次提交数据
    # 局部钩子和全局钩子 ## 局部钩子 ### 什么是局部钩子? 在自定义Form类下面定义一个函数,名字叫:clean_字段名字,内部,取出该字段,进行校验,如果通过,将该字段返回,如果失败,抛出异常(ValidationError) ### 定义局部钩子
    from django import forms
    from django.core.exceptions import ValidationError
    from app01 import models
    
    
    class EmpForm(forms.Form):
        name = forms.CharField(min_length=5, label="姓名", error_messages={
                                                                        "required": "该字段不能为空!",
                                                                        "min_length": "用户名太短。"}
    )
        age = forms.IntegerField(label="年龄")
        salary = forms.DecimalField(max_digits=5, decimal_places=2, label="工资")
    
        # 注意这里函数的名字必须是clean_字段名的形式
        def clean_name(self):  # 局部钩子
            val = self.cleaned_data.get("name")
            # 如果是数字
            if val.isdigit():
                # 抛出异常,使用ValidationError之前要导入
                raise ValidationError("用户名不能是纯数字")
            elif models.Emp.objects.filter(name=val):
                raise ValidationError("用户名已存在!")
            else:
                return val
    
    

    姓名输入纯数字时,显示错误信息 ![](https://img2018.cnblogs.com/blog/1542801/201903/1542801-20190325193924696-1750874306.png)
    输入数据库已存在的姓名时,显示错误信息 ![](https://img2018.cnblogs.com/blog/1542801/201903/1542801-20190325193831756-1465307449.png)
    输入正确的信息时,正常提交


    检查数据库是否写入


    ## 全局钩子 ### 什么是全局钩子? 局部钩子只是校验一个字段是否合法,如果要校验不同字段之间的值,需要使用全局钩子,也就是说,全局钩子是校验不同字段之间的一种方法
    ###定义全局钩子 在EmpForm下面添加一个字段r_salary ```python class EmpForm(forms.Form): # 这里定义的字段和models里面的Emp表的字段必须一一对应 # label的值为input对应的label标签显示的内容 # error_message:验证未通过时显示的信息 name = forms.CharField(min_length=5, label='姓名', error_messages={ # 这里每一个键值对表示对应的字段验证未通过时显示的错误信息 'required': '姓名不同为空', 'min_length': '姓名太短', }) # 定制约束条件 age = forms.IntegerField(label='年龄') salary = forms.DecimalField(max_digits=5, decimal_places=2, label='工资') r_salary = forms.DecimalField(max_digits=5, decimal_places=2, label="请再次输入工资")
    <br>
    定义clean方法
    ```python
    from django import forms
    from app1 import models
    from django.core.exceptions import ValidationError
    
    
    class EmpForm(forms.Form):
        # 这里定义的字段和models里面的Emp表的字段必须一一对应
        # label的值为input对应的label标签显示的内容
        # error_message:验证未通过时显示的信息
        name = forms.CharField(min_length=5, label='姓名', error_messages={
            # 这里每一个键值对表示对应的字段验证未通过时显示的错误信息
            'required': '姓名不同为空',
            'min_length': '姓名太短',
        })  # 定制约束条件
        age = forms.IntegerField(label='年龄')
        salary = forms.DecimalField(max_digits=5, decimal_places=2, label='工资')
        r_salary = forms.DecimalField(max_digits=5, decimal_places=2, label="请再次输入工资")
    
        def clean_name(self):
            val = self.cleaned_data.get('name')
            if val.isdigit():
                raise ValidationError('姓名不能不能全是数字')
            elif models.Emp.objects.filter(name=val):
                raise ValidationError('用户名已存在')
            else:
                return val
    
        def clean(self):
            salary = self.cleaned_data.get('salary')
            r_salary = self.cleaned_data.get('r_salary')
            if salary != r_salary:
                raise ValidationError('工资输入有误')
            else:
                return self.cleaned_data
    

    修改视图函数 ```python from django.shortcuts import render, HttpResponse, redirect from app1.myForm import EmpForm from app1 import models

    def login(request):
    if request.method == 'POST':
    # 把request.POST作为参数传进去
    form = EmpForm(request.POST)
    # 验证数据
    if form.is_valid():
    # 打印验证过的数据(可以写进数据库里)
    data = form.cleaned_data
    # 注意一定要删除多余的数据
    data.pop('r_salary')
    models.Emp.objects.create(**data)
    return Httpresponse('添加成功')
    else:
    # 获取全局错误信息
    clear_errors = form.errors.get('all')
    return render(request, 'login.html', {'form': form, 'clear_errors': clear_errors})
    else:
    form = EmpForm() # 实例化一个EmpForm对象
    # 把form传给前端页面
    return render(request, 'login.html', {'form': form})

    <br>
    两次工资输入不一致时
    ![](https://img2018.cnblogs.com/blog/1542801/201903/1542801-20190325203013010-1350064280.png)
    
    <br>
    ## 小结
    - 局部钩子和全局钩子都是用来<font color='#ff0000'>校验用户输入的数据</font>,校验成功返回对应的值,校验失败主动抛出异常
    - 局部钩子用来校验`某个字段`是否合法,着眼于局部;全局钩子用来校验`多个字段之间`是否满足某种关系(合法性),着眼于全局
    - 局部钩子在前,全局钩子在后
  • 相关阅读:
    HTTP/2之服务器推送(Server Push)最佳实践
    相似人群画像算法
    Linux也有后悔药,五种方案快速恢复你的系统
    IPv6原理、应用与实践
    护航者,腾讯云: 2017年度游戏行业DDoS态势报告—回溯与前瞻
    放大倍数超5万倍的Memcached DDoS反射攻击,怎么破?
    Unity引擎与C#脚本简介
    腾讯云Redis混合存储版重磅推出,万字长文助你破解缓存难题!
    拒绝平庸,以程序员的名义定义新桌面!
    腾讯云EMR大数据实时OLAP分析案例解析
  • 原文地址:https://www.cnblogs.com/zzliu/p/10595140.html
Copyright © 2020-2023  润新知