django2.2-form表单详解

一、form组件

通常情况下,我们需要自己手动在HTML页面中,编写form标签和其内的其它元素。但这费时费力,而且容易出错,数据验证也比较麻烦。

因此,Django在内部集成了一个表单模块,专门用来帮助我们快速处理表单相关的内容。Django的表单模块给我们提供了下面三个主要功能:

  • 准备和重组数据,用于页面渲染;
  • 为数据创建HTML表单元素;
  • 接收和处理用户从客户端提交的表单及数据。

二、form表单的基本语法

编写Django的form表单,非常类似我们在模型系统里编写一个模型。在模型中,一个字段代表数据表的一列,而form表单中的一个字段代表<form>中的一个<input>元素。

1. form表单类的书写

在app文件夹下,新建一个forms.py文件写入:

from django import forms

class MyForm(forms.Form):
    # 最多不能超过20个字符,最少5个字符
    username = forms.CharField(max_length=20, min_length=5)
    password = forms.CharField(max_length=20, min_length=5)
    # 会验证输入是否符合邮箱格式
    email = forms.EmailField()

Form类中的每个字段不仅会验证数据,还会将数据转换为合适的格式。比如,DateField类型的字段会将收到的数据转换为python的datetime.data对象,无论我们传给它的是对象还是字符串,只要是有效的,它都会转换为datetime.data对象。

2. 校验数据

在终端中运行命令python manage.py shell,导入表单类,就可以在终端中进行以下步骤。

  • 创建表单对象:
    实例化表单类,参数为一个字典,键为类属性,值为需要提交的数据。

    form_obj1 = MyForm({'username':'mahugh','password':'123456','email':'123456'})  # email的值不符合邮箱格式
    
    form_obj2 = MyForm({'username':'mahugh','password':'123456','email':'123456@qq.com'})  # 所有值都符合条件
    
  • 查看验证是否通过:

    is_valid()方法,只要有一个键值对不符合验证条件,就返回false

    传入多余的键值对,不会影响验证结果,但少传键值对就会返回false

    form_obj1.is_valid()
    # 返回:False
    
    form_obj2.is_valid()
    # 返回:True
    
  • 查看通过验证的数据:

    cleaned_data只包含合法的(符合验证条件的)数据,多出的和不合法(不符合验证条件的)都不会被包含。

    form_obj1.cleaned_data
    # 返回:{'username': 'mahugh', 'password': '123456'}
    
    
    form_obj2.cleaned_data
    # 返回:{'username': 'mahugh', 'password': '123456', 'email': '123456@qq.com'}
    

    未调用is_valid()方法进行验证的form表单对象,调用cleaned_data属性查看正确的数据时,会报错'xxx' object has no attribute 'form_true'

  • 查看未通过验证的错误信息:

    errors只包含不合法数据的错误信息,多出的和合法的都不会被包含。

    form_obj1.errors
    # 返回:<ul class="errorlist"><li>email<ul class="errorlist"><li>输入一个有效的 Email 地址。</li></ul></li></ul>
    

    errors会被渲染成无序列表。

3. 渲染表单标签

视图中,生成一个表单对象,传递给模板:

def index(request):
    form_obj = MyForm(auto_id=True)
    return render(request, 'index.html', {'form_obj':form_obj})

如果 auto_id 设置为 True,那么表单输出将包括 <label> 标签,并将使用字段名作为每个表单字段的 id属性值,否则,不输出 <label> 标签,不设置id属性

在模板文件中,写入变量:

<form action="" method="post">
    {{ form_obj }}
</form>

这样就会将所有表单字段渲染为input框,并渲染label提示信息。提示信息默认为首字母大写的字段名称。但这种方法,过于死板,所以不常用。先看一些高级语法,之后总结常用写法。
 

高级语法:

  • 只渲染指定表单字段为input框,不渲染提示信息:

    {{ form_obj.username }}
    

    或者,使用循环渲染所有字段为input框:

    {% for obj in form_obj %}
      <!-- obj渲染出来只是一个个的input框 -->
      {{ obj }}
    {% endfor %}
    
  • 只渲染指定字段的提示信息,不渲染input框:

    {{ form_obj.username.label }}
    

    如果想自定义提示信息,可以在表单类中,传入label参数

    class MyForm(forms.Form):
        username = forms.CharField(max_length=20, min_length=5, label='姓名')
    

    这样,提示信息就会变成“姓名”了,而不是“Username”。

  • 使用指定的标签,包裹住字段被渲染后的html代码:

    <!-- 比如,以p标签包裹username字段 -->
    {{ form_obj.username.as_p }}
    

    最终渲染的html代码如下:

    <p>
        <label for="id_username">姓名</label> 
        <input type="text" name="username" maxlength="20" minlength="5" required="" id="id_username">
    </p>
    

    django支持的标签还有:

    <!-- 渲染为无序列表,以li标签进行包裹 -->
    {{ form_obj.as_ul }}
    
    <!-- 渲染为表格,必须放在table标签内 -->
    {{ form_obj.as_table }}
    

三、展示错误信息

测试准备:由于浏览器自带一些简单且容易跳过的验证措施,会干扰我们后端的测试验证,所以先在form标签中设置novalidate属性,来跳过浏览器验证

1. 展示错误信息

  • 首先在视图中使用is_valid()方法,验证后端提交的数据是否合法。合法就做后续步骤,不合法就将页面重新渲染一遍:

    def login_view(self, request):
        # request.POST可以看作是一个字典,因此可以直接用来实例化表单对象
        form_obj = MyForm(request.POS, auto_id=True)
        if form_obj.is_valid():
            return HttpResponse('好耶!验证通过了!')
    	else:
    		# 带着错误信息,再渲染一遍
    	    return render(request, 'index.html', context={'form_obj': form_obj})
    

    不要忘记auto_id=True参数!

  • 然后在模板的合适位置,写入错误信息变量:

    <form action="" method="post" novalidate>
        {% for form_obj in reg_form %}
            <label for="{{ form_obj.auto_id }}">{{ form_obj.label }}:</label>
            {{ form_obj }}
            {% if form_obj.errors %}
                {% for error in form_obj.errors %}
                    <div>{{ error }}</div>
                {% endfor %}
            {% endif %}
        {% endfor %}
    

{{ form_obj.auto_id }}返回字段input框的id属性值,前提是实例化form表单对象时,写了auto_id=True参数。
因为{{ form_obj.errors }}默认是一个无序列表,使用for循环可以更好的展示多条错误信息
也可以写作{{ form_obj.errors.0 }},只获取错误信息的字符串,不显示 • 符号。

2. 自定义错误信息

在表单类的字段中,传入error_messages参数,该参数接收一个字典:

class MyForm(forms.Form):
    username = forms.CharField(max_length=20, min_length=5,
                               error_messages={
                                   'max_length': '最多不能超过20个字符',
                                   'min_length': '最少不能少于5个字符',
                                   'required': '这个东西必须给我回答,不然揍你!'
                               })
    
    # 邮箱比较特殊,需要单独记忆
    email = forms.EmailField(label='邮箱', error_messages={
        'invalid': '这™是邮箱?'
    })

字典当中的键称为“错误信息键”,值为验证失败时提示的错误信息。

required错误信息键,指在设置了required=True时(表示该字段必须填写),没有填写信息,就会提示该键后面的提示信息。

invalid则会在字段自带的验证未通过时,提示后面的信息,比如在上面的例子中,如果填写的不是一个邮箱,则会提示:“这™是邮箱?”。

不同的字段,拥有不同的错误信息键。常用的错误信息键会在字段 参数和类型 中讲到。

3. 动态添加错误信息

add_error()方法向表单特定字段添加错误信息。

form_obj.add_error('字段名', 错误信息)

字段的名称如果为None,error将作为Form.non_field_errors()的一个非字段错误。
错误信息可以是一个字符串,或者最好是 ValidationError 的实例,如:ValidationError("用户名已存在")
注意:Form.add_error()会自动从 cleaned_data 中删除相关字段

四、form表单的钩子函数(HOOK)

钩子函数是一类有特殊用法的函数,它会在特定节点自动触发完成响应操作。分为局部钩子函数和全局钩子函数两类。

1. 局部钩子(只涉及到一个字段)

局部钩子函数的函数名就是clean_字段名,你要给那个字段自定义规则,这个字段名就是谁!
比如:在django表单进行验证时,检查用户名是否含有违规字词(只涉及到username字段):

from django import forms
from django.core.exceptions import ValidationError
from app01.models import UserInfo


class MyForm(forms.Form):
	# 表单字段
	username = forms.CharField(label='用户名', max_length=12, min_length=2)

 # 局部钩子
    def clean_name(self):
    	# 获取用户输入的用户名
        val = self.cleaned_data.get('username')
         # 查看数据库中是否有这个值
        ret = UserInfo.objects.filter(username=val) 
        # 如果在数据库中没有,就通过匹配
        if not ret: 
            return val
        # 否则,说明在数据库中有该用户名
        else:
            raise ValidationError("用户名已存在")

2. 全局钩子(涉及到多个字段)

全局钩子的函数名必须是clean()
比如:在django表单进行验证时,检查两次用户密码是否一致(涉及到password和confirm_password两个字段):

from django import forms
from django.core.exceptions import ValidationError
from app01.models import UserInfo

class MyForm(forms.Form):
	# 表单字段
	password = forms.CharField(label='密码', max_length=18, min_length=6)
	confirm_password = forms.CharField(label='确认密码', max_length=18, min_length=6)
	
 	# 全局钩子
    def clean(self):
    pwd=self.cleaned_data.get("password")  
    r_pwd=self.cleaned_data.get("confirm_password")
    # 上面两个,有可能自带规则或自定义规则未通过,则get取值是空
    if pwd and r_pwd: # 如果两个都通过了第一层说明clean_data中有值就是true
        if pwd==r_pwd:
            return self.cleaned_data
        else:
            raise ValidationError("两次密码不一致")
    else:  
    '''
    如果两个只要有其中一个不在clean_data里,那就没必要在比较了,
    因为本身就已经在errors里了
    '''
        return self.cleaned_data

五、字段参数和类型

1. 核心参数

  • label:用来自定义表单的提示信息(label标签的文本)。

  • error_messages:用于自定义验证不通过时的提示信息,在上面的自定义错误信息一节中已经讲过。

  • initial:用来给字段设置默认值,对应input标签的value属性。

  • required:指定该字段是否是必须填写的,默认值为true,表示该字段必须填写,否则不能通过验证。

widget参数

为字段指定一个Widget类,它有以下作用:

  • 指定部件,对应的是input的type属性:

    widget=forms.TextInput  # 普通文本类型
    widget=forms.PasswordInput  # 密码类型
    widget=forms.EmailInput  # 邮箱类型
    

    较为复杂的部件:

    • 单选按钮RadioSelect(对应radio):

      gender = forms.fields.ChoiceField(
          choices=((1, "男"), (2, "女"), (3, "保密")),
          label="性别",
          initial=3,
          widget=forms.RadioSelect()
      )
      
    • 选择框CheckboxInput(对应checkbox):

      # 单选框
      keep = forms.ChoiceField(
          label="是否记住密码",
          initial="checked",
          widget=forms.CheckboxInput()
      )
      
      # 多选框
      hobby = forms.MultipleChoiceField(
          choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
          label="爱好",
          initial=[1, 3],
          widget=forms.CheckboxSelectMultiple()
      )
      
    • 下拉框CheckboxInput(对应option):

      # 单选下拉框
      hobby = forms.ChoiceField(
          choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
          label="爱好",
          initial=3,
          widget=forms.Select()
      )
      
      # 多选下拉框
      hobby = forms.MultipleChoiceField(
          choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
          label="爱好",
          initial=[1, 3],
          widget=forms.SelectMultiple()
      )
      

    更多内置部件参考官方文档:传送门

  • 传入参数,多用于设置标签的属性值:
    比如设置class属性,使用attrs参数:

    widget=forms.TextInput(
        attrs={'class': 'c1 c2 c3'}
    )
    

validators参数

给字段提供一个验证函数列表,用于自定义验证规则:

from django.core.exceptions import ValidationError

# 这个东西是用来翻译东西的
from django.utils.translation import gettext_lazy as _

def check_username(value):
    # 阿巴阿巴,验证操作……
    if 阿巴阿巴:
        # 验证不通过,抛出异常
        raise ValidationError(
                # 错误信息,翻译用不用看你自己
                _('%(value)这玩意得这个样子才行'),
                params={'value': value},
            )

class MyForm():
     username = forms.CharField(validators=[check_username])

之后,username字段就会使用check_username函数进行验证。django还自带了一些验证器,比如RegexValidator验证器可以帮助我们通过正则表达式,快速书写验证方法:

validators=[
    # 参数为正则表达式和错误信息
    RegexValidator(r'我是正则表达式', '你这玩意不符合我这个正则表达式啊')
    ]

更多内置验证器参考官方文档:传送门

其他参数

  • help_text='': 帮助信息(在标签旁边显示)
  • localize=False:是否支持本地化
  • disabled=False:是否可以编辑
  • label_suffix=None:Label内容后缀

2. 常用类型

  • BooleanField

    • 默认部件:CheckboxInput
    • 空值:False
    • 规范化为:Python 的 TrueFalse 值。
    • 如果字段有 required=True,则验证该值是否为 True (例如,复选框被选中)。
    • 错误信息键:required
  • CharField

    • 默认部件:TextInput

    • 空值:empty_value的值。

    • 规范化为:一个字符串。

    • 如果提供了 max_lengthmin_length,则验证输入的字符数。否则,所有输入都有效。

    • 错误信息键:requiredmax_lengthmin_length

    • 可选参数:

      max_length:最大字符数。

      min_length:最小字符数。

      strip:如果 True (默认),该值将被去掉前面和末尾的空白。

      empty_value:用来表示“空”的值。默认为空字符串。

  • IntegerField

    Field.localizeFalse 时是 NumberInput 否则,该字段的默认表单部件是 TextInput 否则,该字段的默认表单部件是 TextInput

    • 空值:None

    • 规范化为:Python 的整数。

    • 验证给定值是否为整数。

    • 错误信息键:requiredinvalidmax_valuemin_value

    • 可选参数:

      max_value:最大值。

      min_value:最小值。

  • DecimalField

    Field.localizeFalse 时是 NumberInput否则,该字段的默认表单部件是 TextInput

    • 空值:None

    • 规范化为:Python 的 decimal

    • 验证给定值是否为十进制。如果提供了 max_valuemin_value,则额外验证值的范围。前面和后面的空格会被忽略。

    • 错误信息键:requiredinvalidmax_valuemin_valuemax_digitsmax_decimal_placesmax_whole_digits

    • 可选的参数:

      max_value=None:最大值。
      min_value=None:最小值。

      max_digits:最大数字总位数。

      decimal_places:小数位数。

  • DateField

    • 默认部件:DateInput

    • 空值:None

    • 规范化为:Python 的 datetime.date 对象。

    • 验证给定值是 datetime.datedatetime.datetime 或以特定日期格式化的字符串。

    • 格式:“2015-09-01”

    • 错误信息键:requiredinvalid

    • 可选的参数:

      input_formats:用于将字符串转换为有效的 datetime.date 对象的格式列表,使用的是time模块的那一套格式化方法。

  • TimeField

    DateField基本相同,只有格式不同:“11:12”

  • DateTimeField

    DateField基本相同,只有格式不同:“2015-09-01 11:12”

  • EmailField

    • 默认部件:EmailInput

    • 空值:empty_value` 的值。

    • 规范化为:一个字符串。

    • 使用 EmailValidator来验证给定的值是一个有效的电子邮件地址,使用一个适度复杂的正则表达式。

    • 错误信息键:requiredinvalid:输入内容不符合邮箱格式时提示的错误信息。

    • 可选参数:

      max_lengthmin_lengthempty_value,它们的工作原理与 CharField 一样。

  • FileField

    • 默认部件:ClearableFileInput

    • 空值:None

    • 规范化为:一个 UploadedFile 对象,它将文件内容和文件名包装成一个单一对象。

    • 可以验证非空文件数据已经绑定到表单中。

    • 错误信息键:requiredinvalidmissingemptymax_length

    • 可选的验证参数:

      max_length :文件名的最大长度。

      allow_empty_file:是否允许文件内容为空。

    更多表单字段类型参考官方文档:传送门

  • 5
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

花_城

你的鼓励就是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值