python---django中form组件(数据添加前使用自定义方法<django预留扩展点3个>进行验证,以及源码分析)
form组件代码:
from app02.models import Userfrom django.core.exceptions import ValidationError class AjaxForm(forms.Form):
user = fields.CharField(
required=True,
min_length=,
max_length=,
)
email = fields.EmailField(
required=True,
) #自定义方法 clean_字段名
#必须返回值self.cleaned_data['user']
#如果出错抛出raise ValidationError("error...")
#会在基础验证成功后,使用自定义方法进行验证
#扩展点1
#验证用户名唯一
def clean_user(self):
v = self.cleaned_data['user']
if User.objects.filter(username=v).count():
#重复了
raise ValidationError("用户名已存在")
return v
#验证邮箱....未完成
def clean_email(self): return self.cleaned_data['email']
#扩展点2
def clean(self):
#self.cleaned_data中含有所有成功验证数据
value_dict = self.cleaned_data
v1 = value_dict.get('user')
v2 = value_dict.get("email")
# if User.objects.filter(username=v1,email=v2).count():
# #重复了
# raise ValidationError("username and email is exists")
if v1=="root123" and v2=="66666da@qq.com":
raise ValidationError("username and email is exists")
return self.cleaned_data
如果在数据库中发现重复数据,抛出错误。
views代码:
def ajax(req):
if req.method == "GET":
obj = AjaxForm()
return render(req,"ajax.html",{"obj":obj})
else:
ret={}
obj = AjaxForm(req.POST)
if obj.is_valid(): #在使用is_valid之后才会将数据进行验证
ret['status']="OK"
return HttpResponse(json.dumps(ret))
else:
print(obj.errors)
ret['message']=obj.errors
return HttpResponse(json.dumps(ret))
在is_valid后开始验证代码,从此处进入
源码查看:
class BaseForm:
def is_valid(self):
"""
Returns True if the form has no errors. Otherwise, False. If errors are
being ignored, returns False.
"""若是表单数据正确,则返回true
return self.is_bound and not self.errors #是属性方法,进行字段验证
self.is_bound = data is not None or files is not None #data传入表单数据不为空,所以is_bound=true
考虑self.errors:
@property
def errors(self):
"Returns an ErrorDict for the data provided for the form"#返回错误信息为表单数据
if self._errors is None: #初始self._errors是null
self.full_clean() #进入该方法
return self._errors
追踪self.full_clean():
def full_clean(self):
"""
Cleans all of self.data and populates self._errors and
self.cleaned_data.
"""
self._errors = ErrorDict() #初始化错误字典
if not self.is_bound: # Stop further processing.
return
self.cleaned_data = {} #初始化正确数据
# If the form is permitted to be empty, and none of the form data has
# changed from the initial data, short circuit any validation.
if self.empty_permitted and not self.has_changed(): #如果允许为空,并且数据为从初始状态进行改变,则直接返回
return
#下面是开始验证的方法
self._clean_fields()
self._clean_form()
self._post_clean()
开始验证字段:self._clean_fields()
def _clean_fields(self):
#循环字段,在form组件中设置的字段,该字段来自于DeclarativeFieldsMetaclass的__new__
for name, field in self.fields.items():
# value_from_datadict() gets the data from the data dictionaries.
# Each widget type knows how to retrieve its own data, because some
# widgets split data over several HTML fields.
if field.disabled:
value = self.get_initial_for_field(field, name)
else:
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
try:
if isinstance(field, FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
#上面尝试进行正则验证,验证成功后,开始下面逻辑
#会调用 clean_%s方法name是字段名,这就是我们的自定义方法,我们可以在已经满足正则验证后的数据
#上再次进行自定义函数的验证,比如验证数据库数据的唯一性处理
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value #注意:最终的值取决于自定义方法:前提是已经存在该方法
except ValidationError as e: #在自定义方法上,如果验证出错,我们需要抛出该错误让该方法进行捕获
self.add_error(name, e)
这里进行循环字段验证,一次验证一个字段,而且字段顺序按照form组件中定义字段的顺序。
可以看上面使用方法clean_user
但是对于联合唯一,差了点。
继续进行流程分析:(前提是前面没有抛出错误)
分析def full_clean(self):中的第二个方法:self._clean_form()
def _clean_form(self):
try:
cleaned_data = self.clean()
except ValidationError as e:
self.add_error(None, e)
else:
if cleaned_data is not None:
self.cleaned_data = cleaned_data
其中调用了self.clean()方法:
def clean(self):
""" #预留钩子函数,在此处可以进行验证,出错抛出ValidationError错误 但是信息字段名是__all__,不是某一个字段名,比如user
#第一个方法是针对某一个,那个key就是对应字段名(单个字段错误验证),第二个方法是针对所有字段(整体错误验证),所有是__all__
Hook for doing any extra form-wide cleaning after Field.clean() has been
called on every field. Any ValidationError raised by this method will
not be associated with a particular field; it will have a special-case
association with the field named '__all__'.
"""
return self.cleaned_data
其中由于第一个方法成功,所以self.cleaned_data中含有所有字段信息,此处可以对所有字段一起进行验证
也是一个扩展点
可以看上面方法clean使用:
补充:
def _clean_form(self):
try:
cleaned_data = self.clean()
except ValidationError as e:
self.add_error(None, e)
#此处添加错误时是None为字段名,为什么在后面变为__all__
else:
if cleaned_data is not None:
self.cleaned_data = cleaned_data
查看代码add_error
def add_error(self, field, error):
error = {field or NON_FIELD_ERRORS: error.error_list}
查看字段名NON_FIELD_ERRORS :空的定义
NON_FIELD_ERRORS = '__all__'
公共错误信息放在__all__中(不是字段验证产生的错误信息放置位置)
错误信息存放形式,以字典存放 {
__all__:[],
字段名1:[],
字段名2:[],
字段名3:[],
....
}
分析第三个方法:self._post_clean()
def _post_clean(self):
"""
An internal hook for performing additional cleaning after form cleaning
is complete. Used for model validation in model forms.
"""
pass
这个方法也是一个扩展点,但是没有像前两个方法一样做错误捕获,我们需要自己做,由于前两个基本内容可以完成,这个可以不需要
python---django中form组件(数据添加前使用自定义方法<django预留扩展点3个>进行验证,以及源码分析)的更多相关文章
- Django中Form组件的使用
Form介绍 HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入 ...
- django中form组件
Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...
- Django中form组件的is_valid校验机制
先来归纳一下整个流程(1)首先is_valid()起手,看seld.errors中是否值,只要有值就是flase(2)接着分析errors.里面判断_errors是都为空,如果为空返回self.ful ...
- django框架中form组件的简单使用示例:注册验证
Django中form组件的三大特点: 1. 生成页面可使用的HTML标签 2. 对用户提交的数据进行初步校验 3. 保留上次输入内容 废话不多说,直接进入正题. 这是注册界面截图: 与上一篇a ...
- django 之(二) --- 源码分析
CBV类视图继承 CBV:继承自View:注册的时候使用的as_view() 入口 不能使用请求方法的名字作为参数的名字 只能接受已经存在的属性对应的参数 定义了一个view 创建了一个类视图对象 保 ...
- 图解Janusgraph系列-图数据底层序列化源码分析(Data Serialize)
图解Janusgraph系列-图数据底层序列化源码分析(Data Serialize) 大家好,我是洋仔,JanusGraph图解系列文章,实时更新~ 图数据库文章总目录: 整理所有图相关文章,请移步 ...
- HDFS源码分析数据块校验之DataBlockScanner
DataBlockScanner是运行在数据节点DataNode上的一个后台线程.它为所有的块池管理块扫描.针对每个块池,一个BlockPoolSliceScanner对象将会被创建,其运行在一个单独 ...
- 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据 | 百篇博客分析OpenHarmony源码 | v33.02
百篇博客系列篇.本篇为: v33.xx 鸿蒙内核源码分析(消息队列篇) | 进程间如何异步传递大数据 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁 ...
- angular源码分析:injector.js文件分析——angular中的依赖注入式如何实现的(续)
昨天晚上写完angular源码分析:angular中jqLite的实现--你可以丢掉jQuery了,给今天定了一个题angular源码分析:injector.js文件,以及angular的加载流程,但 ...
随机推荐
- Egret(白鹭引擎)——“TypeError: Cannot read property 'asCom' of null”
前言 相信我,这个错误新手都不陌生:TypeError: Cannot read property 'asCom' of null 还有,一定要看我上一篇,哦不(人家应该是报了这个错,才找到看到这篇文 ...
- chrome浏览器插件 Octotree 让你浏览GitHub的时候像IDE 一样提供项目目录
GitHub 作为代码托管平台,竟然没有提供项目目录,方便用户在线快速浏览项目结构.所以,在线分析项目源码就会变得很繁琐,必须一层一层点击,然后再一次一次地向上返回.要知道,本来 GitHub 网站在 ...
- nginx 新增域名访问
nginx 新增域名访问 1.申请阿里云域名 2.指向阿里云主机 3.配置nginx文件 server { listen 80; server_name zlx.test.com; set $root ...
- 使用pyspark模仿sqoop从oracle导数据到hive的主要功能(自动建表,分区导入,增量,解决数据换行符问题)
最近公司开始做大数据项目,让我使用sqoop(1.6.4版本)导数据进行数据分析计算,然而当我们将所有的工作流都放到azkaban上时整个流程跑完需要花费13分钟,而其中导数据(增量)就占了4分钟左右 ...
- android开发之使用SQLite数据库存储
http://blog.csdn.net/jason0539/article/details/16360835 SQLite 介绍 SQLite 一个非常流行的嵌入式数据库,它支持 SQL 语言,并且 ...
- 《Linux内核分析》 第六周
<Linux内核分析> 第6周 一.进程的描述 1.进程控制块PCB 2.linux下的进程转化图 TASK_RUNNING可以是就绪态或者执行态,具体取决于系统调用 TASK_ZOMBI ...
- Haskell(一 )------ Windos下环境配置
1.去官网下载安装包 2.然后运行安装包路径最好就不要改了. 3.打开命令行输入 cabal user-config init 会出现默认的放置配置文件的地址,然后到那个文件夹下修改config文件. ...
- GS 服务器端开启webservice 远程调试的方法
1. 修改 安装目录下 web.config的文件. 一般目录为: C:\Program Files\GenerSoft\bscw_local\web.config 为了保证安全想把文件备份一下. 2 ...
- Java中String直接赋字符串和new String的区别 如String str=new String("a")和String str = "a"有什么区别?
百度的面试官问 String A="ABC"; String B=new String("ABC"); 这两个值,A,B 是否相等,如果都往HashSet里面放 ...
- Session, Cookie区别
答: 1.Session由应用服务器维护的一个服务器端的存储空间:Cookie是客户端的存储空间,由浏览器维护. 2.用户可以通过浏览器设置决定是否保存Cookie,而不能决定是否保存Session, ...