forms组件最大的作用,就是做数据校验。

普通做法,一个一个写校验规则,没有解耦。校验规则,都在视图函数里面。

网页校验

修改urls.py,增加路径addbook

from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
path('addbook/', views.addbook),
]

修改views.py,增加addbook视图函数,完整代码如下:

from django.shortcuts import render,HttpResponse

# Create your views here.
from django import forms # 必须导入模块
class UserForm(forms.Form): # 必须继承Form
#限制数据为字符串,最小长度4,最大长度12
name = forms.CharField(min_length=4,max_length=12)
age = forms.IntegerField() # 限制为数字
#限制长度为11位
tel = forms.CharField(min_length=11,max_length=11) def index(request):
return render(request,"index.html") def addbook(request):
if request.method == "POST":
# 将post数据传给UserForm
form = UserForm(request.POST)
if form.is_valid(): # 验证数据
print("success")
else:
print("fail")
return HttpResponse("ok")
return render(request,"addbook.html")

templates新增addbook.html

做表单校验的时候,一定要注意,表单的name和class的属性必须一一对应

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>添加用户</h3>
<form action="" method="post">
{% csrf_token %}
<lable>姓名</lable><input type="text" name="name"/><br/>
<lable>年龄</lable><input type="text" name="age"/><br/>
<lable>邮箱</lable><input type="text" name="email"/><br/>
<lable>手机号码</lable><input type="text" name="tel"/>
<br/>
<input type="submit">
</form>
</body>
</html>

网页访问添加页面,输出信息

提交之后,效果如下:

Pycharm控制台输出:success

空表单直接提交

Pycharm控制台输出:fail

initial 初始值,input框里面的初始值。

error_messages 重写错误信息

form django import forms
from django.core.validators import RegexValidator
from django.core.exceptions import ValidationError
class RegForm(forms.Form): name = forms.Charfield(
initail = 'xxx'
label = '用户名',
min_length = 8,
required = False,
widget = forms.TextInput(attrs={'class':'form-control'})#可以写PasswordInput
#widget=forms.widgets.RadioSelect()单选Select() 多选SelectMultiple()
error_message= {
'min_length':'最小长度为8',
}
#复杂校验
1.直接加自定义验证规则或者写局部钩子
user = fields.CharField(
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
) def clean_tel(self):#局部钩子
val = self.cleaned_data.get("tel")
if len(val) == 11: # 判断长度
return val
else:
raise ValidationError("手机号码必须11位") def clean_name(self):
# self.cleaned_data.get('name') # 校验成功 返回当前字段值
# 不成功 抛出异常
raise ValidationError() def clean(self):
# 校验成功 返回所有的值
# 不成功 抛出异常
self.add_error('字段','错误信息')
raise ValidationError() def clean(self): # 全局钩子
pwd = self.cleaned_data.get("pwd")
r_pwd = self.cleaned_data.get("r_pwd")
if pwd and r_pwd and pwd != r_pwd: # 判断2次密码不为空,并且2次密码不相等
raise ValidationError("两次密码不一致")
else:
return self.cleaned_data # 这句是固定写法,不能变动

form.is_valid() 它做了2件事情:

1.将数据传给form
2.将验证数据拆分到2个容器中

self.cleaned_data= {} 表示干净的数据
self.error = {} 表示验证不通过的数据

self表示UserForm类的实例对象

as_p是一个特殊的属性,常见的有:

  • {{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中
  • {{ form.as_p }} 将它们渲染在<p> 标签中
  • {{ form.as_ul }} 将它们渲染在<li> 标签中

Widgets

Widget 是Django 对HTML 输入元素的表示。Widget 负责渲染HTML和提取GET/POST 字典中的数据。

如果你想让某个Widget 实例与其它Widget 看上去不一样,你需要在Widget 对象实例化并赋值给一个表单字段时指定额外的属性(以及可能需要在你的CSS 文件中添加一些规则)

注意:当input属性为password时,是不会渲染的!除此之外,其他的表单元素,是可以渲染的

显示错误信息

field.errors 表示错误列表。因为是列表,会有很多错误信息

field.errors.0 表示接收第一个错误信息。一般取第一个即可!

局部钩子与全局钩子

上面提到的校验规则是forms组件自带的。 它做了一些简单的校验功能,比如判断字符串,纯数字,邮箱等等。

比如要求用户名,必须包含字母和数字。年龄必须要大于18岁,手机号码要以136,137开头...

这些需求,默认的校验规则是做不到的。

def clean_name(self):
val = self.cleaned_data.get("name") # 获取输入的用户名 if not val.isdigit(): # 判断不是数字类型
return val
else:
raise ValidationError("用户名不能是纯数字")

注意:

clean_name  这个名字是有含义的,不能随便定义。name表示UserForm类的属性。clean表示校验

val 表示用户输入的用户名

val.isdigit() 表示判断输入的是否为数字,必须return 一个值

raise 表示主动报错,必须接ValidationError。

局部钩子只能校验一个字段,那么2个字段校验呢?比如密码和确认密码必须一致,这个时候,需要使用全局钩子

如何定义全局钩子呢?查看源代码

is_valid()-->self.errors-->self.full_clean()-->self._clean_form()-->self.clean()

Django内置字段

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类型
...

Django内置插件

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

实例案例

urls.py

urlpatterns = [
# url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
url(r'^adduser/', views.adduser),
]

form.py

from django import forms  # 必须导入模块
from django.forms import widgets
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError #用于密码验证 class UserForm(forms.Form): # 必须继承Form
# 定义变量,专门给text类型的输入框添加class
wid = widgets.TextInput(attrs={"class": "form-control"})
# 定义字典,错误信息显示中文
# 限制数据为字符串,最小长度4,最大长度12
error_hints = {"required": "该字段不能为空", "invalid": "格式错误!"}
name = forms.CharField(min_length=4, max_length=12, label="姓名", widget=wid, error_messages=error_hints)
# 密码字段
pwd = forms.CharField(label="密码", widget=widgets.PasswordInput(attrs={"class": "form-control"}),
error_messages=error_hints) r_pwd = forms.CharField(label="确认密码", widget=widgets.PasswordInput(attrs={"class": "form-control"}),
error_messages=error_hints)
# 限制为数字
age = forms.IntegerField(label="年龄", widget=wid, error_messages=error_hints)
# 限制为邮箱格式
email = forms.EmailField(label="邮箱", widget=widgets.EmailInput(attrs={"class": "form-control"}),
error_messages=error_hints)
# 限制长度为11位
tel = forms.CharField(max_length=11, label="手机号码", widget=wid, error_messages=error_hints) def clean_name(self): # 校验name值
val = self.cleaned_data.get("name") # 获取输入的用户名 if not val.isdigit(): # 判断数字类型
return val
else:
raise ValidationError("用户名不能是纯数字") def clean_tel(self):
val = self.cleaned_data.get("tel")
if len(val) == 11: # 判断长度
return val
else:
raise ValidationError("手机号码必须11位") def clean_age(self):
val = self.cleaned_data.get("age")
if int(val) > 18: # input输入的值为字符串,必须转换为int
return val
else:
raise ValidationError("年龄必须满18岁以上!") def clean(self): # 全局钩子
pwd = self.cleaned_data.get("pwd")
r_pwd = self.cleaned_data.get("r_pwd")
if pwd and r_pwd and pwd != r_pwd: # 判断2次密码不为空,并且2次密码不相等
raise ValidationError("两次密码不一致")
else:
return self.cleaned_data # 这句是固定写法,不能变动

views.py

from django.shortcuts import render, HttpResponse
from app01.form import UserForm # 导入UserForm类 # Create your views here.
def index(request):
return render(request, "index.html") def adduser(request):
if request.method == "POST":
# 将post数据传给UserForm
form = UserForm(request.POST)
print(request.POST)
if form.is_valid(): # 验证数据 1.将数据传给form 2.将验证数据拆分到2个容器中
print("###success###")
print(form.cleaned_data) # 所有干净的字段以及对应的值
# ErrorDict : {"校验错误的字段":["错误信息",]}
print(form.errors)#表示验证不通过的数据
print(type(form.errors)) # 打印类型
return HttpResponse("添加成功")
else:
print("###fail###")
# print(form.cleaned_data)
print(form.errors)
# # 获取email错误信息,返回一个错误列表,可以切片
# print(form.errors.get("email"))
# # 获取第一个错误信息
# print(form.errors.get("email")[0])
g_error = form.errors.get("__all__") # 接收全局钩子错误信息
if g_error: # 判断有错误信息的情况下
g_error = g_error[0] # 取第一个错误信息 # 将form和g_error变量传给adduser.html
return render(request, "adduser.html", {"form": form, "g_error": g_error}) else: # 默认是get请求(地址栏输入访问时)
form = UserForm() # 没有表单数据的form
return render(request, "adduser.html", {"form": form})

adduser.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
<style>
.error {
color: red;
}
</style>
</head>
<body> <div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-2">
<h3>添加用户</h3><br/>
<form action="" method="post" novalidate>
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label for="">{{ field.label }}</label>
{{ field }} <span class="error pull-right">{{ field.errors.0 }}</span>
{% if field.label == "确认密码" %}
<span class="error pull-right">{{ g_error|default_if_none:"" }}</span>
{% endif %}
</div>
{% endfor %}
<br/>
<input type="submit" class="btn btn-success btn-sm">
</form>
</div>
</div>
</div> </body>
</html>

点击提交什么都不输入的情况下

校验

ModelForm

form与model的终极结合。

class BookForm(forms.ModelForm):

    class Meta:
model = models.Book
fields = "__all__"
labels = {
"title": "书名",
"price": "价格"
}
widgets = {
"password": forms.widgets.PasswordInput(attrs={"class": "c1"}),
}

class Meta:下常用参数:

model = models.Student  # 对应的Model中的类
fields = "__all__" # 字段,如果是__all__,就是表示列出所有的字段
exclude = None # 排除的字段
labels = None # 提示信息
help_texts = None # 帮助提示信息
widgets = None # 自定义插件
error_messages = None # 自定义错误信息

python django(forms组件)的更多相关文章

  1. Django forms组件里的ChoiceField、ModelChoiceField和ModelMutipleChoiceField的区别

    阅读简要 首先我们要明白Django forms组件里的ChoiceField.ModelChoiceField和ModelMutipleChoiceField是继承关系 ChoiceField 1. ...

  2. Django forms组件与钩子函数

    目录 一.多对多的三种创建方式 1. 全自动 2. 纯手撸(了解) 3. 半自动(强烈推荐) 二.forms组件 1. 如何使用forms组件 2. 使用forms组件校验数据 3. 使用forms组 ...

  3. django ---forms组件

    forms组件 本文目录 1 校验字段功能 2 渲染标签功能 3 渲染错误信息功能 4 组件的参数配置 5 局部钩子 6 全局钩子 回到目录 1 校验字段功能 针对一个实例:注册用户讲解. 模型:mo ...

  4. Python - Django - form 组件内置的正则校验器

    app01/models.py: from django.db import models class UserInfo(models.Model): username = models.CharFi ...

  5. Python - Django - form 组件基本用法

    普通 form 表单的处理: reg.html: <!DOCTYPE html> <html lang="en"> <head> <met ...

  6. Python - Django - form 组件动态从数据库取 choices 数据

    app01/models.py: from django.db import models class UserInfo(models.Model): username = models.CharFi ...

  7. Python - Django - form 组件自定义校验

    reg2.html: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  8. Python - Django - form 组件校验功能

    app01/models.py: from django.db import models class UserInfo(models.Model): username = models.CharFi ...

  9. Python - Django - form 组件常用的字段和字段参数

    邮箱: views.py: from django import forms from django.forms import widgets class RegForm(forms.Form): e ...

随机推荐

  1. 启动期间的内存管理之bootmem_init初始化内存管理–Linux内存管理(十二)

    1. 启动过程中的内存初始化 首先我们来看看start_kernel是如何初始化系统的, start_kerne定义在init/main.c?v=4.7, line 479 其代码很复杂, 我们只截取 ...

  2. Python 位操作运算符

    & 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 (a & b) 输出结果 12 ,二进制解释: 0000 1100 | 按位或运算符:只要对应的二 ...

  3. 2017 百度杯丶春秋欢乐赛 writeup

    1. 内涵图(Misc) 题目: 我不是一个简单的图片 我是一个有内涵的图片 解:保存到桌面,右键属性->详细信息,即可获得flag. 2. 小电影(Misc) 题目: 我说过 这次比赛是让大家 ...

  4. 爬虫实例系列一(requests)

    一 爬虫简介 ''' 爬虫:通过编写程序,模拟浏览器上网,让其去互联网上爬取数据的过程 分类: 通用爬虫:爬取全部的页面数据 聚焦爬虫:抓取页面中局部数据 增量式爬虫:爬取网站中更新出的数据 反爬机制 ...

  5. Hadoop从入门到精通系列之--0.Hadoop生态体系

    https://blog.csdn.net/Haidaiya/article/details/84568588#%E4%B8%80%20%E5%A4%A7%E6%95%B0%E6%8D%AE%E7%9 ...

  6. redis分页摘抄

    Redis 笔记与总结8 PHP + Redis 信息管理系统(分页+好友关注) 分页 要对列表页进行分页,需要知道: ①用户总数 $count ② 页大小 $pageSize:用户自定义 ③ 当前页 ...

  7. 解决chrome安装谷歌访问助手错误问题

    解决chrome安装谷歌访问助手错误问题 针对新版本安装谷歌访问助手插件报错问题 1.下载谷歌访问助手 http://www.ggfwzs.com/ 2.chrome浏览器打开发者模式 3.将下载的c ...

  8. SQL其他常用的语句

    阅读目录 一:汇总数据 1.理解AVG函数 2.理解COUNT()函数 3.理解max()函数 4.理解min()函数 5.理解sum()函数 二:分组数据 1 创建分组(group by) 2 HA ...

  9. ORM框架的前世今生

    目录 一.ORM简介二.ORM的工作原理三.ORM的优缺点四.常见的ORM框架 一.ORM简介 ORM(Object Relational Mapping)对象关系映射,一般指持久化数据和实体对象的映 ...

  10. svn 钩子应用 - svn 提交字符限制, 不能为空

    一.版本库钩子 1.1 start-commit  开始提交的通知 输入参数:传递给你钩子程序的命令行参数,顺序如下: 1.  版本库路径 2.  认证过的尝试提交的用户名 3.  Depth,mer ...