文章目录
- 前期准备
- 表单基础使用
- 创建表单
- 表单类型
- Field
- CharField(Field)
- IntergerField(Field)与 FloatField(Filed)
- DecimalField(Field)
- BaseTemporalField(Field)
- RegexField(Field)
- EmailField(Field)
- FileField(Field)
- ImageField(Field)
- URLField(Field)
- BooleanField(Field)与NullBooleanField(Field)
- ChoiceField(Field)与TypedChoiceField(ChoiceField)
- MultipleChoiceField(ChoiceField)与TypedMultipleChoiceField(MultipleChoiceField)
- ComboField(Field)
- MultiValueField(Field)
- SplitDateTimeField(MultiValueField)
- FilePathField(Field)
- GenericIPAddressField(CharField)
- SlugField(CharField)
- UUIDField(CharField)
- 常用验证器
- HTML插件
- 自定义验证
- 调用表单
前期准备
在学习表单前,如果你已经对django的数据库模型有所了解,那么表单对来说应该也比较好入手,最好对前端的表单也有一定的了解,方便写测试dome。
前端准备
这里我使用前后分类模式的开发进行。
当前前端,我使用vue/cli配合element制作。这里暂不放源码了。之后大家可以做个简单的输入框尝试表单接收。并且为了使用后端from验证,我将前端所以验证进行了关闭。
表单基础使用
Django中的表单丰富了传统的HTML语言中的表单。在Django中的表单,主要做以下两件事
- 渲染表单模板。
- 表单验证数据是否合法。
创建表单
我们首先在Django的APP中自己创建一个文件,名字最好是froms.py
。
首先我们从Django中引入froms库from django import forms
然后继承forms.Form
就可以创建表单类
from django import forms
class 邮箱登陆(forms.Form):
# 账号(邮箱)
account = forms.EmailField()
# 密码,设置一个最小六位,最大十八位的限制
password = forms.CharField(min_length=6, max_length=18)
从上述实例中可以看出,表单和数据库模型是比较相似的。如果你了解数据库模型,那么表单对你来说也很容易上手。
表单类型
Field
所有表单的父类,一般不会主动调用,内置字段(方法中的属性)可用于所有表单,下列特殊标记的为后端工程师必须掌握的内置字段
内置字段以及默认值 | 作用 |
---|---|
required=True | 是否为必填项 |
widget=None | HTML插件(主要作用与前端) |
label=None | 用于生成Lable(标签)或显示内容(主要作用与前端) |
initial=None | 初始值(主要作用与前端) |
help_text='' | 帮助信息,在标签旁边显示(主要作用与前端) |
error_messagrs=None | 错误信息 |
show_hidden_initial=False | 是否在当前插件后面再加一个隐藏的且具有默认值的插件(主要作用与前端,如验证两次输入是否一致) |
validators=[] | 自定义验证规则(下方详细介绍) |
localize=False | 是否支持本地化(根据不同语言地区访问用户显示不同语言) |
disabled=False | 是否禁用(主要作用与前端,生成禁用的输入框) |
label_suffix=None | label(标签)内容后缀(主要作用与前端) |
CharField(Field)
存储字符类型数据的表单
内置字段以及默认值 | 作用 |
---|---|
max_length=None | 最大长度 |
min_length=None | 最小长度 |
strip=True | 是否移除用户输入空白(这里只会移除输入开头和结尾的空白) |
IntergerField(Field)与 FloatField(Filed)
IntergerField
用于存入整数,FloatField
用于存入浮点数
内置字段以及默认值 | 作用 |
---|---|
max_value=None | 最大值 |
min_value=None | 最小值 |
DecimalField(Field)
DecimalField
存入小数与FloatField
用于存入浮点数不同的是,DecimalField
更加精确,如果涉及到金钱计算,选择DecimalField
内置字段以及默认值 | 作用 |
---|---|
max_value=None | 最大值 |
min_value=None | 最小值 |
max_digits=None | 总长度 |
decimal_places=None | 保留小数的位数 |
BaseTemporalField(Field)
存储字符类型数据的表单
内置字段以及默认值 | 作用 |
---|---|
input_formats=None | 时间格式化 |
常用的时间都继承与此类:
日期: DateField(BaseTemporalField)
格式:2020-08-01
时间: TimeField(BaseTemporalField)
格式:11:12
日期时间: DateTimeField(BaseTemporalField)
格式:2015-09-01 11:12
持续时间: DurationField(Field)
时间间隔:%d %H:%M:%S.%f
RegexField(Field)
用于存入正则表达式(自动验证是否为正则表达式)
内置字段以及默认值 | 作用 |
---|---|
regex | 自定制正则表达式 |
max_length=None | 最大长度 |
min_length=None | 最小长度 |
EmailField(Field)
用于存入电子邮件(自动验证电子邮件格式)
无内置字段
FileField(Field)
存储文件
内置字段以及默认值 | 作用 |
---|---|
allow_empty_file=False | 是否允许空文件 |
ImageField(Field)
存储图片(自动验证是否为图片)
使用此表单验证,需要下载PIL模块(pillow
库,pip install Pillow
)。
- form表单中 enctype=“multipart/form-data”
- view函数中 obj = MyForm(request.POST, request.FILES)
URLField(Field)
存储URL链接(自动验证是否为URL链接)
BooleanField(Field)与NullBooleanField(Field)
存储布尔类型数据,其中NullBooleanField
为非空布尔值
ChoiceField(Field)与TypedChoiceField(ChoiceField)
单选框,其中TypedChoiceField
为允许手动输入的单选框,单选框插件默认为selectwidget=select
内置字段以及默认值 | 作用 |
---|---|
choices=() | 选项,如:choices = ((0,‘索尼’),(1,‘微软’),) |
coerce = lambda val: val | 对选中的值进行一次转换,通过lambda函数实现(只对TypedChoiceField 生效) |
empty_value= '' | 空值的默认值(只对TypedChoiceField 生效) |
MultipleChoiceField(ChoiceField)与TypedMultipleChoiceField(MultipleChoiceField)
多选框,其中TypedMultipleChoiceField
为允许手动输入的多选框,默认插件为selectwidget=select
内置字段以及默认值 | 作用 |
---|---|
coerce = lambda val: val | 对选中的值进行一次转换,通过lambda函数实现(只对TypedMultipleChoiceField 生效) |
empty_value= '' | 空值的默认值(只对TypedMultipleChoiceField 生效) |
ComboField(Field)
联合表单验证,可以一次调用多种验证
内置字段以及默认值 | 作用 |
---|---|
fields=() | 使用多个验证 |
如: fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
验证一个最大长度在20以内的邮箱。
MultiValueField(Field)
抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合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(Field)
文件选项,目录下文件显示在页面中
内置字段以及默认值 | 作用 |
---|---|
path | 文件夹路径 |
match=None | 正则匹配 |
recursive=False | 递归下面的文件夹 |
allow_files=True | 允许文件 |
allow_folders=False | 允许文件夹 |
GenericIPAddressField(CharField)
通用IP地址
内置字段以及默认值 | 作用 |
---|---|
protocol='both' | both,ipv4,ipv6支持的IP格式 |
unpack_ipv4=False | 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用 |
SlugField(CharField)
数字0-9
,字母a-z
,下划线_
与减号(连体符)-
UUIDField(CharField)
uuid类型
常用验证器
使用表单中的validators
属性,我们可以自定义一个字段的验证属性,使用自定义验证器的时候,我们需要先引入from django.core import validators
常用的验证器 | 作用 |
---|---|
MaxValueValidator | 验证最大值。 |
MinValueValidator | 验证最小值。 |
MinLengthValidator | 验证最小长度。 |
MaxLengthValidator | 验证最大长度。 |
EmailValidator | 验证是否是邮箱格式。 |
URLValidator | 验证是否是URL格式。 |
RegexValidator | 验证正则表达式。 |
比如我当前想要验证一个手机号,就可以通过下列方式验证
class 电话号登陆(forms.Form):
# 账号(电话号)
account = forms.CharField(validators=[validators.RegexValidator("1[345678]\d{9}")])
HTML插件
HTML插件 | 作用 |
---|---|
TextInput(Input) | 常规文本输入框input type="text" |
NumberInput(TextInput) | 数字输入框 |
EmailInput(TextInput) | 邮箱输入框 |
URLInput(TextInput) | url输入框 |
PasswordInput(TextInput) | 密码输入框 |
HiddenInput(TextInput) | 隐藏输入框 |
Textarea(Widget) | textarea文本域 |
DateInput(DateTimeBaseInput) | 日期输入框 |
DateTimeInput(DateTimeBaseInput) | 日期时间输入框 |
TimeInput(DateTimeBaseInput) | 时间输入框 |
CheckboxInput | 多选框 |
Select | 下拉框 |
NullBooleanSelect | 非空布尔值下拉框 |
SelectMultiple | 多选下拉框 |
RadioSelect | 单选框 |
CheckboxSelectMultiple | 复选框 |
FileInput | 文件上传 |
ClearableFileInput | |
MultipleHiddenInput | 多隐藏输入框 |
SplitDateTimeWidget | 时间分割框(两个input框) |
SplitHiddenDateTimeWidget | |
SelectDateWidget |
自定义验证
有时候对一个字段验证,不是一个长度,一个正则表达式能够写清楚的,还需要一些其他复杂的逻辑,那么我们可以对某个字段,进行自定义的验证。比如在注册的表单验证中,我们想要验证手机号码是否已经被注册过了,那么这时候就需要在数据库
(这里我使用的是Django的数据库模型调用MySQL(MySQL8.0.12)数据库。)中进行判断才知道。
碰到这种情况,我们可以自定义一个验证器,自定义验证器也很简单,使用一个函数即可自定义,def clean_自定义字段(self)
,其中自定义字段
必须是传入的值中的一个,比如说我先在要自定义邮箱字段
在使用自定义验证中def clean_自定义字段(self)
我们可以使用self.cleaned_data
获取传入的值;并且使用forms.ValidationError("错误信息")
传入报错信息
比如我当前想验证注册的邮箱在数据库中是否已经存在:
""".froms.py"""
from django import forms
from .models import 用户信息
class 注册账号(forms.Form):
# 邮箱
input_inf = forms.EmailField()
# 验证账号时候已经存在在数据库中
def clean_input_inf(self):
print('表单中的信息', self.cleaned_data)
input_inf = self.cleaned_data.get('input_inf')
exists = 用户信息.objects.filter(电子邮箱=input_inf).exists()
if exists:
raise forms.ValidationError("电子邮箱已经存在")
return input_inf
""".views.py"""
from django.views import View
from django.http import JsonResponse
from .froms import 注册账号
# 调用表单的方法下方会详细讲解
class 注册(View):
def post(self, request):
表单 = 注册账号(request.POST)
if 表单.is_valid():
return JsonResponse({'注册': '成功'})
else:
return JsonResponse({'注册': '失败'})
多字段验证方法
上述表单介绍中,我们介绍过联合表单验证ComboField(Field)
,可以一次调用多种验证,但如果我们验证的时候需要调用多个字段(如:注册时的密码与确认密码框)就可以用到多字段验证。多字段验证的方法和上述自定义验证较为相似,使用def clean(self)
即可,自定义验证中使用的方法,在多字段验证同样也可以使用。
比如我当前项目需要验证注册时用户需要填写邮箱或者手机号其中的一个。
def clean(self):
电子邮箱 = self.cleaned_data.get('email')
手机号 = self.cleaned_data.get('telephone')
if 电子邮箱:
pass
elif 手机号:
pass
else:
raise forms.ValidationError("手机号与邮箱必须选填一个")
调用表单
创建完成表单后,我们在调用的时候需要先引入表单,类似引入数据库模型,比如上述表单我在同一个APP的视图中引入只需使用from .froms import 邮箱登陆
,如果是引入其他APP中的表单,则改变路径即可from APP.froms import 表单类
。
引入后,我们需要先向后端定义的表单中传入前端用户输入的表单值,比如表单 = 邮箱登陆(request.POST)
这里使用的是POST方式传输。
表单常用方法 | 作用 |
---|---|
.cleaned_data | 获取表单中传入的数据 |
.is_valid() | 判断是否通过了表单验证 |
.errors | 使用ui标签返回错误信息 |
.errors.as_json() | 使用json格式返回错误信息(进行了url编码) |
.errors.get_json_data() | 没有进行url编码的json格式 |
.errors.as_data() | 单纯返回错误信息 |
.errors.as_text() | 只返回错误文本 |
non_field_errors() | 返回与特定字段无关的错误的错误列表。(上述errors能用的方法,这里也能用) |
from django.views import View
from django.http import JsonResponse
from .froms import 注册账号
class 注册(View):
def post(self, request):
表单 = 注册账号(request.POST)
if 表单.is_valid():
print(表单.cleaned_data)
return JsonResponse({'注册信息': '成功'}, json_dumps_params={'ensure_ascii': False})
else:
print("0:", 表单.cleaned_data)
print("1:", 表单.errors)
print("2:", 表单.errors.as_json())
print("3:", 表单.errors.get_json_data())
print("4:", 表单.errors.as_data())
print("5:", 表单.errors.as_text())
print("6:", 表单.non_field_errors())
print("7:", 表单.non_field_errors().get_json_data())
return JsonResponse({'注册信息': '失败'}, json_dumps_params={'ensure_ascii': False})
如果是一个前后端不分离的项目,可能会常用到.as_table()
、.as_ul()
、.as_p()
,分别是已table标签,ui标签,p标签返回数据。