form(form基础、标签渲染、错误显示 重置信息、form属性、局部钩子、全局钩子)
阅读原文时间:2023年07月09日阅读:1

Django中的Form使用时一般有两种功能:

1、生成html标签

2、验证输入内容

要想使用django提供的form,要在views里导入form模块

  from django import forms

首先我们创建我们的模版



Title

普通方式

{% csrf\_token %}



然后我们来定义一个form 类,以及我们需要掌握的一些基础知识,这些代码全部写在 试图页面里。

from django.shortcuts import render,HttpResponse
from django.forms import widgets

Create your views here.

from django.forms import widgets
from django import forms

#创建form表单验证规则
class UserForm(forms.Form):
name = forms.CharField(min_length=4)
pwd = forms.CharField(min_length=6)
r_pwd = forms.CharField(min_length=6)
email = forms.EmailField()

def index(request):
if request.method == 'POST':
form = UserForm(request.POST)
#如果输入全部符合规则判断为真将结果传递给 changed_data,并打印
print('form.is_vaild---------',form.is_valid())
if form.is_valid():
print(form.changed_data)
#如果失败,打印为真的值,打印错误,获取错误字典中name 的错误值。
else:
print(form.cleaned_data)
print('错误信息的类型---------',type(form.errors))
print(form.errors)
print(form.errors.get('name'))
return HttpResponse('ok')
form=UserForm()

return render(request,'index.html',locals())

如果输入正确的验证信息

后台输出

form.is_vaild--------- True

{'name': '召唤精灵', 'pwd': '1111111111', 'r_pwd': '1111111111', 'email': 'asdas@dsad.com'}

可以看出输入符合验证条件的数据, is_vaild  会返回 True  ,然后正确信息会存储到cleaned_data 中

下面输入一下错误验证信息

form.is_vaild--------- False
错误信息的类型---------
获取错误信息字典

  • name
    • Ensure this value has at least 4 characters (it has 3).

  • Ensure this value has at least 4 characters (it has 3).

可以看到类型是已字典到形式存储到,然后咱们通过字典到的取值方法 get 取到验证错误到报错信息。

如果同时有错误有正确会怎么样

form.is_vaild--------- False
{'pwd': '11111111111', 'r_pwd': '1111111111', 'email': 'asdas@dsad.com'}
错误信息的类型---------
获取错误信息字典

  • name
    • Ensure this value has at least 4 characters (it has 3).

  • Ensure this value has at least 4 characters (it has 3).

虽然验证失败了,但是cleaned_data中保留了正确的验证信息。

form内置字段

创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

Field
required=True, 是否允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
help_text='', 帮助信息(在标签旁边显示)
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
validators=[], 自定义验证规则
localize=False, 是否支持本地化
disabled=False, 是否可以编辑
label_suffix=None Label内容后缀

CharField(Field)
max_length=None, 最大长度
min_length=None, 最小长度
strip=True 是否移除用户输入空白

IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值

FloatField(IntegerField)

DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 总长度
decimal_places=None, 小数位长度

BaseTemporalField(Field)
input_formats=None 时间格式化

DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12

DurationField(Field) 时间间隔:%d %H:%M:%S.%f

RegexField(CharField)
regex, 自定制正则表达式
max_length=None, 最大长度
min_length=None, 最小长度
error_message=None, 忽略,错误信息使用 error_messages={'invalid': '…'}

EmailField(CharField)

FileField(Field)
allow_empty_file=False 是否允许空文件

ImageField(FileField)

注:需要PIL模块,pip3 install Pillow
以上两个字典使用时,需要注意两点:
- form表单中 enctype="multipart/form-data"
- view函数中 obj = MyForm(request.POST, request.FILES)

URLField(Field)

BooleanField(Field)

NullBooleanField(BooleanField)

ChoiceField(Field)

choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示

ModelChoiceField(ChoiceField)
… django.forms.models.ModelChoiceField
queryset, # 查询数据库中的数据
empty_label="---------", # 默认空显示内容
to_field_name=None, # HTML中value的值对应的字段
limit_choices_to=None # ModelForm中对queryset二次筛选

ModelMultipleChoiceField(ModelChoiceField)
… django.forms.models.ModelMultipleChoiceField

TypedChoiceField(ChoiceField)
coerce = lambda val: val 对选中的值进行一次转换
empty_value= '' 空值的默认值

MultipleChoiceField(ChoiceField)

TypedMultipleChoiceField(MultipleChoiceField)
coerce = lambda val: val 对选中的每一个值进行一次转换
empty_value= '' 空值的默认值

ComboField(Field)
fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式
fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])

MultiValueField(Field)
PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用

SplitDateTimeField(MultiValueField)
input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']

FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
required=True,
widget=None,
label=None,
initial=None,
help_text=''

GenericIPAddressField
protocol='both', both,ipv4,ipv6支持的IP格式
unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用

SlugField(CharField) 数字,字母,下划线,减号(连字符)

UUIDField(CharField) uuid类型

注:UUID是根据MAC以及当前时间等创建的不重复的随机字符串

>>> import uuid

# make a UUID based on the host ID and current time  
>>> uuid.uuid1()    # doctest: +SKIP  
UUID('a8098c1a-f86e-11da-bd1a-00112444be1e')

# make a UUID using an MD5 hash of a namespace UUID and a name  
>>> uuid.uuid3(uuid.NAMESPACE\_DNS, 'python.org')  
UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e')

# make a random UUID  
>>> uuid.uuid4()    # doctest: +SKIP  
UUID('16fd2706-8baf-433b-82eb-8c7fada847da')

# make a UUID using a SHA-1 hash of a namespace UUID and a name  
>>> uuid.uuid5(uuid.NAMESPACE\_DNS, 'python.org')  
UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d')

# make a UUID from a string of hex digits (braces and hyphens ignored)  
>>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}')

# convert a UUID to a string of hex digits in standard form  
>>> str(x)  
'00010203-0405-0607-0809-0a0b0c0d0e0f'

# get the raw 16 bytes of the UUID  
>>> x.bytes  
b'\\x00\\x01\\x02\\x03\\x04\\x05\\x06\\x07\\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f'

# make a UUID from a 16-byte string  
>>> uuid.UUID(bytes=x.bytes)  
UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')

内直插件

TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget

方式一

方式一

{% csrf\_token %}
{{ form.name }}
{{ form.pwd }}
{{ form.r\_pwd }}
{{ form.email }}

方式二

需要给form验证条件,添加 label属性

class UserForm(forms.Form):
name = forms.CharField(min_length=4,label='用户名')
pwd = forms.CharField(min_length=6,label='密码')
r_pwd = forms.CharField(min_length=6,label='确认密码')
email = forms.EmailField(label='邮箱')

方式二



{% csrf_token %}
{% for foo in form %}
{{ foo }}

{% endfor %}  
<input type="submit">

方式三

方式三

{% csrf\_token %} {{ form.as\_p }}

小结:

虽然这三种标签渲染的方式 第三种最为简介方便,但是局限性也最大,不能根据自己的需求调整标签,只能使用他提供的方法,如果常用的话还是选择第二种标签渲染方式。

将用户输入错误的信息在模板进行显示,用户提交后不会因为用户有错误信息而清空用户的输入内容,增加用户体验。

试图

def index(request):

if request.method == 'POST':  
    form = UserForm(request.POST)  
    if form.is\_valid():  
        print(form.cleaned\_data)

    else:  
        print(form.cleaned\_data)  
        print(form.errors)  
        #这里将用户已经输入的值,重新传递给模板,用户输入过的内容不会刷新,增加用户体验。  
    return render(request,'index.html',locals())  
form = UserForm()

return render(request,'index.html',locals())

模板



forms

form验证

{% csrf\_token %} {% for foo in form %}

{{ foo }} {{ foo.errors.0 }}

{% endfor %}



修改模板标签类型

class BooleanField(**kwargs):
默认的Widget:CheckboxInput
空值:False
规范化为:Python 的True 或 False。
如果字段带有required=True,验证值是否为True(例如复选框被勾上)。
错误信息的键:required

class CharField(**kwargs):
默认的Widget:TextInput
空值:''(一个空字符串)
规范化为:一个Unicode 对象。
如果提供,验证max_length 或min_length。 否则,所有的输入都是合法的。
错误信息的键:required, max_length, min_length
有两个参数用于验证:

max_length
min_length
如果提供,这两个参数将确保字符串的最大和最小长度。

charFied input()

class ChoiceField(**kwargs)¶
默认的Widget:Select
空值:''(一个空字符串)
规范化为:一个Unicode 对象。
验证给定的值在选项列表中存在。
错误信息的键:required, invalid_choice
invalid_choice 错误消息可能包含%(value)s,它将被选择的选项替换掉。

接收一个额外的必选参数:choices
用来作为该字段选项的一个二元组组成的可迭代对象(例如,列表或元组)或者一个可调用对象。
例如:
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
)

ChoiceField (select标签)

class DateField(**kwargs):
默认的Widget:DateInput
空值:None
规范化为:一个Python datetime.date 对象。
验证给出的值是一个datetime.date、datetime.datetime 或指定日期格式的字符串。
错误信息的键:required, invalid
接收一个可选的参数:

input_formats
一个格式的列表,用于转换一个字符串为datetime.date 对象。

DateField Dateinput 标签

class EmailField(**kwargs)
默认的Widget:EmailInput
空值:''(一个空字符串)
规范化为:一个Unicode 对象。
验证给出的值是一个合法的邮件地址,使用一个适度复杂的正则表达式。
错误信息的键:required, invalid
具有两个可选的参数用于验证,max_length 和min_length。如果提供,这两个参数确保字符串的最大和最小长度。

emailField EaillInput

class FileField(**kwargs)¶
默认的Widget:ClearableFileInput
空值:None
规范化为:一个UploadedFile 对象,它封装文件内容和文件名为一个单独的对象。
可以验证非空的文件数据已经绑定到表单。
错误信息的键:required, invalid, missing, empty, max_length
具有两个可选的参数用于验证,max_length 和 allow_empty_file。如果提供,这两个参数确保文件名的最大长度,而且即使文件内容为空时验证也会成功。

FileField

class ImageField(**kwargs)¶
默认的Widget:ClearableFileInput
空值:None
规范化为: An UploadedFile object that wraps the file content and file name into a single object.
验证文件数据已绑定到表单,并且该文件具有Pillow理解的图像格式。
错误信息的键:required, invalid, missing, empty, invalid_image
使用ImageField需要安装Pillow并支持您使用的图像格式。如果在上传图片时遇到损坏 图像错误,通常意味着Pillow不了解其格式。要解决这个问题,请安装相应的库并重新安装Pillow。

ImageField

class MultipleChoiceField(**kwargs)¶
默认的Widget:SelectMultiple
空值:[](一个空列表)
规范化为:一个Unicode 对象列表。
验证给定值列表中的每个值都存在于选择列表中。
错误信息的键:required, invalid_choice, invalid_list
invalid_choice错误消息可能包含%(value)s,将替换为所选择的选项。

对于ChoiceField,需要一个额外的必需参数choices。

MultipleChoiceField (select标签 multiple)

编辑模板标签属性

class CommentForm(forms.Form):
name = forms.CharField(widget=forms.TextInput(attrs={'class': 'special'}))
url = forms.URLField()
comment = forms.CharField(widget=forms.TextInput(attrs={'size': '40'}))

编辑错误信息显示.

class RegForm(forms.Form):
username = forms.CharField(
min_length=3,
label="用户名",
help_text=‘‘,
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
)
password = forms.CharField(
min_length=3,
label="密码",

    help\_text=‘6~16个字符,区分大小写‘,  
    error\_messages={  
        "required": "不能为空",  
        "invalid": "格式错误",  
    },  
    widget=forms.widgets.PasswordInput  
)

re\_password = forms.CharField(  
    min\_length=3,  
    label="确认密码",

    help\_text=‘请再次填写密码‘,  
    error\_messages={  
        "required": "不能为空",  
        "invalid": "格式错误",  
    },  
    widget=forms.widgets.PasswordInput)

gender = forms.fields.ChoiceField(  
    choices=((1, "男"), (2, "女"), (3, "保密")),  
    label="性别",  
    initial=3,  
    widget=forms.widgets.RadioSelect  
)

phone = forms.fields.CharField(  
    label="电话",  
    error\_messages={  
        "required": "不能为空",  
    },  
)

email = forms.fields.CharField(  
    label=‘邮箱‘,  
    help\_text=‘6~18个字符,可使用字母、数字、下划线‘,  
    widget=forms.widgets.EmailInput,  
    error\_messages={  
        "required": "不能为空",  
        "invalid": "格式错误",  
    },  
)

# 批量给form表单里的字段加样式  
def \_\_init\_\_(self, \*args, \*\*kwargs):  
    super().\_\_init\_\_(\*args, \*\*kwargs)  
    for field in iter(self.fields):  
        field\_obj = self.fields\[field\]  
        if not isinstance(field\_obj, forms.fields.ChoiceField):  
            field\_obj.widget.attrs.update({‘class‘: ‘form-control‘})

# 全局钩子,此处用来判断两次输入的密码  
def clean(self):  
    pwd = self.cleaned\_data.get(‘pwd‘)  
    re\_pwd = self.cleaned\_data.get(‘re\_pwd‘)  
    if pwd != re\_pwd:  
        self.add\_error(‘re\_pwd‘, ‘两次密码不一致‘)  
        raise ValidationError(‘两次密码不一致‘)  
    else:  
        return self.cleaned\_data

# 局部钩子函数,写给phone的校验函数  
def clean\_phone(self):  
    phone = self.cleaned\_data.get(‘phone‘)  
    if not re.findall(‘^1\[0-9\]{10}$‘, phone):  
        raise ValidationError("格式错误!")  
    else:  
        return phone

我理解的钩子就是在 cleaned_data 中在进行逻辑处理,也就是说对通过form 校验的数值再次进行逻辑处理。

#局部钩子,钩子是在form规则对象正确的情况下才执行的程序  
def clean\_name(self):  
    val = self.cleaned\_data.get('name')  
    print('val----------',val)#clean\_\[key\]  为固定写法

if not val.isdigit(): #如果正确直接返回改值 return val else: #否则返回错误信息 raise ValidationError('不能为纯数字')

视图

from django.shortcuts import render, HttpResponse

Create your views here.

from django import forms
from django.forms import widgets
from django.forms import ValidationError

class UserForm(forms.Form):
name = forms.CharField(
min_length=4,
label='用户名',
error_messages={'required': '不能为空'})
pwd = forms.CharField(
min_length=4,
widget=widgets.PasswordInput
)
email = forms.EmailField(label='邮箱')

# 局部钩子,钩子是在form规则对象正确的情况下才执行的程序  
def clean\_name(self):  # clean\_\[key\]  为固定写法  
    val = self.cleaned\_data.get('name')  
    print('val----------', val)

    if not val.isdigit():  
        return val  
    else:  
        raise ValidationError('不能为纯数字')

# 全局钩子,与局部钩子不同的是,对比多个已经校验过的数据。  
def clean(self):  
    name = self.cleaned\_data.get('name')  
    pwd = self.cleaned\_data.get('pwd')  
    if name == pwd:  
        print('no')  
        raise ValidationError('用户名和密码不能一致')  
    else:  
        print('ok')  
        return self.cleaned\_data

def index(request):
if request.method == 'POST':
form = UserForm(request.POST)
if form.is_valid():
print(form.cleaned_data)

    else:  
        clean\_error = form.errors.get('\_\_all\_\_')  # 获取所有错误信息  
        # 这里将用户已经输入的值,重新传递给模板,用户输入过的内容不会刷新,增加用户体验。  
        print(clean\_error, type(clean\_error))  
    return render(request, 'index.html', locals())  
form = UserForm()

return render(request, 'index.html', locals())

模板



forms

全局钩子

{% csrf\_token %} {% for field in form %}
{{ field }} {% if field.label == '密码' %} {{ clean\_error.0 }} {% endif %} {{ field.errors.0 }}
{% endfor %}



效果