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

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})


在前端页面里用form对象生成html标签

login.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



姓名输入纯数字时,显示错误信息
1542801-20190325193924696-1750874306.png



输入数据库已存在的姓名时,显示错误信息
1542801-20190325193831756-1465307449.png



输入正确的信息时,正常提交

1542801-20190325194158985-1458728546.png
检查数据库是否写入
1542801-20190325194313776-1767283979.png


全局钩子

什么是全局钩子?

局部钩子只是校验一个字段是否合法,如果要校验不同字段之间的值,需要使用全局钩子,也就是说,全局钩子是校验不同字段之间的一种方法

定义全局钩子

在EmpForm下面添加一个字段r_salary

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="请再次输入工资")



定义clean方法

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



修改视图函数

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})



两次工资输入不一致时
1542801-20190325203013010-1350064280.png


小结

  • 局部钩子和全局钩子都是用来校验用户输入的数据,校验成功返回对应的值,校验失败主动抛出异常
  • 局部钩子用来校验某个字段是否合法,着眼于局部;全局钩子用来校验多个字段之间是否满足某种关系(合法性),着眼于全局
  • 局部钩子在前,全局钩子在后

转载于:https://www.cnblogs.com/zzliu/p/10595140.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值