二、Form操作

一般会创建forms.py文件,单独存放form模块。

Form 专门做数据验证,而且非常强大。有以下两个插件:

  • fields :验证(肯定会用的)
  • widgets:生成HTML(有时候用,有时候可以不用)
    • 一般新url方式操作用widgets,因为生成url不是关键的,可以保留上一次提交的数据
    • Ajax请求的时候,可以不用它生成html

1.1、Form操作动态Select数据

urls.py

url(r'^index/$', views.index),

views.py

def index(request):
from cmdb.forms import UserInfoForm
obj = UserInfoForm()
return render(request, 'index.html', {'obj':obj})

forms.py

from django import forms
from django.forms import widgets, fields
from cmdb import models class UserInfoForm(forms.Form):
user = fields.CharField(
required=False,
widget=widgets.Textarea(attrs={'class':'c1'})
)
pwd = fields.CharField(
max_length=12,
widget=widgets.PasswordInput(attrs={'class':'c1'})
)
user_type = fields.ChoiceField(
# choices=[(1,'普通用户'),(2,'超级用户')], # 手动填写
choices=models.UserType.objects.values_list('id','name'), # 数据库中获取
widget=widgets.Select
)

models.py

class UserType(models.Model):
name = models.CharField(max_length=32)

index.html

<body>
<p>{{ obj.user }}</p>
<p>{{ obj.pwd }}</p>
<p>{{ obj.user_type }}</p>
<p>{{ obj.user_type2 }}</p>
</body>

上面有个问题,就是数据库添加数据后,django需要重启网页才能看到新加的数据。why?

forms里面,定义的类,类里的user、pwd、user_type都是静态字段(类变量),这些都是属于类的。

__init__里面写的属于对象。

而启动Django的时候,类变量一次性都加在到内存了。

上面views.py里的obj = UserInfoForm()生成了一个对象,会执行类里的__init__方法,会把类里的字段封装到obj.fields里面(里面有user、pwd、user_type三个字段),所以:

views.py

def index(request):

    from cmdb.forms import UserInfoForm
from cmdb import models obj = UserInfoForm()
obj.fields['user_type'].choices = models.UserType.objects.values_list('id','name') return render(request, 'index.html', {'obj':obj})

这样,数据库添加数据,网页上就可以实时更新了。但是如果有很多choices的话,也会写很多,也不好。

所以不在views.py里做修改,可以在forms.py里类的__init__构造方法里写

forms.py

from django import forms
from django.forms import widgets, fields
from cmdb import models class UserInfoForm(forms.Form):
user = fields.CharField(
required=False,
widget=widgets.Textarea(attrs={'class':'c1'})
)
pwd = fields.CharField(
max_length=12,
widget=widgets.PasswordInput(attrs={'class':'c1'})
)
user_type = fields.ChoiceField(
# choices=[(1,'普通用户'),(2,'超级用户')], # 手动填写
choices=[], # 构造方法里取,这里只定义就可以了,不需要在获取一次。
widget=widgets.Select
) #### 另外一种写法 方式 ####
user_type2 = fields.ChoiceField(
widget=widgets.Select(choices=[])
) def __init__(self, *args, **kwargs):
super(UserInfoForm,self).__init__(*args, **kwargs) self.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
#### 另外一种写法 方式 ####
self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id','name')

1.2、Form操作动态Select数据

上面1.1里是自己获取实现的,Django也可以自动实现,只是实现的不太好。

django 里自动实现的,看user_type3

from django import forms
from django.forms import widgets, fields
from django.forms.models import ModelChoiceField
from cmdb import models class UserInfoForm(forms.Form):
user = fields.CharField(
required=False,
widget=widgets.Textarea(attrs={'class':'c1'})
)
pwd = fields.CharField(
max_length=12,
widget=widgets.PasswordInput(attrs={'class':'c1'})
)
user_type = fields.ChoiceField(
choices=[],
widget=widgets.Select
)
user_type2 = fields.ChoiceField(
widget=widgets.Select(choices=[])
)
user_type3 = ModelChoiceField(
queryset=models.UserType.objects.all()
) def __init__(self, *args, **kwargs):
super(UserInfoForm,self).__init__(*args, **kwargs) self.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id','name')

使用Django自动提供的这个方法,有一点不好的就是:需要自己在models里加上__str__方法

class UserType(models.Model):
name = models.CharField(max_length=32) def __str__(self):
return self.name

ModelChoiceField 参数

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

ModelChoiceField 是单选的,多选的是:ModelMultipleChoiceField

2、Form内置钩子(数据验证)

初始化操作

加一个字典,生成显示默认值

views.py

def index(request):
from cmdb.forms import UserInfoForm
obj = UserInfoForm({'user':'lgeng','user_type':''}) # 默认值
return render(request, 'index.html', {'obj':obj})

数据验证

views.py

def index(request):

    from cmdb.forms import UserInfoForm

    if request.method == 'GET':
obj = UserInfoForm({'user':'lgeng','user_type':''})
return render(request, 'index.html', {'obj':obj})
elif request.method == 'POST':
obj = UserInfoForm(request.POST, request.FILES) # request.FILES:接收文件
obj.is_valid() # 数据验证

正则表达式验证成功了,但是如果用户名重复了,也是不让执行的,如何自定制呢?

注册数据验证示例

forms.py

from django.core.exceptions import ValidationError
class RegisterForm(forms.Form):
user = fields.CharField
email = fields.EmailField def clean_user(self): # 对user做一个单独的验证
c = models.UserType.objects.filter(name=self.cleaned_data['user'])
if c : # 如果用户名已经存在,提示报错信息
raise ValidationError('用户名已经存在',code='xxx')
else: # 不存在,验证通过
return self.cleaned_data['user']
def clean_email(self): # 对email做单独的验证
# 验证必须要有返回值
return self.cleaned_data['email'] # 验证顺序:
# 先user字段,在clean_user方法
# 再email字段,在clean_email方法

登录数据验证示例

forms.py

class LoginForm(forms.Form):
user = fields.CharField
# 这里也可以validators=[],自定义正则数据验证
email = fields.EmailField(validators=[]) def clean_user(self):
pass
def clean_pwd(self):
pass
# 当用户名和密码验证整体错误,报错给下面的方法
def clean(self):
c = models.User.objects.filter(name=self.cleaned_data.get('user'),pwd=self.cleaned_data.get('pwd'))
if c:
return self.cleaned_data
else:
raise ValidationError("用户名或密码错误") # 自定义一些其他验证操作
def _post_clean(self):
pass

验证顺序

这么多钩子,这么强大的数据验证,验证顺序是:

form循环,

  • 先第一个字段正则表达式判断,执行字段钩子函数;
  • 第二个字段正则,第二个的钩子;
  • 所有字段完成后,执行clean钩子;
  • clean执行完后,执行_post_clean钩子

怎么去记:通过看源码去找:

先找is_valid,找到errors,找到full_clean,所有的钩子基于full_clean执行的

验证完成后

views.py(伪代码)

def register(request):
from cmdb.forms import RegisterForm
from django.core.exceptions import NON_FIELD_ERRORS
obj = RegisterForm(request.POST)
if obj.is_valid():
obj.cleand_data else:
obj.errors
{
'user':[{'code':'required','message':'xxxx'}],
'pwd':[{'code':'required','message':'xxxx'}],
# 上面每个字段的错误信息放在里面,那clean总的错误信息放在哪里?
'__all__':[], # 特殊的整体错误信息,放在这里
# NON_FIELD_ERRORS:[], 和 __all__ 一个意思。
}

3、Form内置序列化错误信息

不管提交数据是浏览器提交、还是curl方式,还是ajax提交,只要是request.POST都可以做验证。

Ajax 提交数据,进行验证

urls.py

   url(r'^login.html$', views.login),

views.py

from django import forms
from django.forms import widgets, fields
class LoginForm(forms.Form):
username = fields.CharField()
password = fields.CharField(
max_length=64,
min_length=12
) def login(request):
import json
res = {'status':True, 'error':None, 'data': None}
if request.method == "GET":
return render(request,"login.html")
elif request.method == "POST":
obj = LoginForm(request.POST)
if obj.is_valid():
print(obj.cleand_data)
else:
# print(obj.errors, type(obj.errors))
res['error'] = obj.errors.as_json() # 转为json格式
return HttpResponse(json.dumps(res))

login.html

<body>
<form id="fm">
{% csrf_token %}
<p><input type="text" name="username" /></p>
<p><input type="password" name="password" /></p>
<a id="submit">ajax提交</a>
</form>
<script src="/static/jquery-1.12.4.js"></script>
<script>
// 页面框架加载完自动执行
$('#submit').click(function(){
$.ajax({
url:'/login.html',
type:'POST',
data:$('#fm').serialize(),
success:function(arg){
console.log(arg);
arg = JSON.parse(arg); // 转为字典
console.log(arg);
},
error: function(){ }
})
})
</script>
</body>

上面的方式可以实现,只是前端需要反解两次,不太好,下面优化一下。

  • as_json : 生成json格式
  • as_data : 生成dict数据。

views.py

from django import forms
from django.forms import widgets, fields
class LoginForm(forms.Form):
username = fields.CharField()
password = fields.CharField(
max_length=64,
min_length=12
) # 序列化,转换为指定数据类型
import json
from django.core.exceptions import ValidationError
class JsonCustomEncoder(json.JSONEncoder):
def default(self, field):
if isinstance(field, ValidationError):
return {'code':field.code, 'messages': field.messages}
else:
return json.JSONEncoder.default(self, field) def login(request):
res = {'status':True, 'error':None, 'data': None}
if request.method == "GET":
return render(request,"login.html")
elif request.method == "POST":
obj = LoginForm(request.POST)
if obj.is_valid():
print(obj.cleand_data)
else:
# print(obj.errors, type(obj.errors))
# res['error'] = obj.errors.as_json() # 转为json格式
print(type(obj.errors.as_data()))
for k,v in obj.errors.as_data().items():
print(k,v) # 这里v是ValidationError类型,不能序列化
res['error'] = obj.errors.as_data()
result = json.dumps(res, cls=JsonCustomEncoder)
return HttpResponse(json.dumps(result))

4、Django 序列化操作

Json.dumps用来做序列化,但是只能序列化一些简单的基本数据类型。对于无法序列化的数据类型,只能自定制了。

ErrorDict自定义JSONEncoder

由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:

import json
from datetime import date
from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): def default(self, field): if isinstance(field, datetime):
return o.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(field, date):
return o.strftime('%Y-%m-%d') # 转成字符串类型
else:
return json.JSONEncoder.default(self, field) v = {'k':'', "k1":datetime.datetime.now()}
ds = json.dumps(v, cls=JsonCustomEncoder)

QuerySet 第一种序列化方式

上面自己写实现也可以,不过Django提供了方法做序列化

from django.core import serializers

v = models.tb.objects.all()
data = serializers.serialize("json", v)

QuerySet 第二种序列化方式

import json
from datetime import date
from datetime import datetime class JsonCustomEncoder(json.JSONEncoder): def default(self, field): if isinstance(field, datetime):
return field.strftime('%Y-%m-%d %H:%M:%S')
elif isinstance(field, date):
return field.strftime('%Y-%m-%d')
else:
return json.JSONEncoder.default(self, field) v = models.tb.objects.values('id','name','ctime')
v = list(v) # 把(类似列表的queryset类型)转换为列表
v = json.dumps(v,cls=JsonCustomEncoder) # 这里cls只对ctime操作。
# 如果没有ctime这个类型,只写上边的三句就可以实现

注:form里__all__整体的错误信息,前端展示如下:{{ obj.non_field_errors }}


转载请务必保留此出处:http://www.cnblogs.com/lgeng/articles/7366370.html

<!-- END  -->

《版本说明》: 本文转自 -- http://blog.csdn.net/fgf00/article/details/5469502

Django(八)下:Model操作和Form操作、序列化操作的更多相关文章

  1. django(6)model表语句操作、Form操作、序列化操作

    1.model建表操作之创建索引.元数据 # 单表操作,创建表 class User(models.Model): name = models.CharField(max_length=32) ema ...

  2. Django(八)上:Model操作和Form操作

    ↑↑↑点上面的”+”号展开目录 Model和Form以及ModelForm简介 Model操作: 创建数据库表结构 操作数据库表 做一部分的验证 Form操作: 数据验证(强大) ModelForm ...

  3. Django(十八)Model操作补充

    参考博客:http://www.cnblogs.com/wupeiqi/articles/6216618.html 1. 创建类 class UserInfo(model.Model): age = ...

  4. Python之路-(Django(csrf,中间件,缓存,信号,Model操作,Form操作))

    csrf 中间件 缓存 信号 Model操作 Form操作 csrf: 用 django 有多久,我跟 csrf 这个概念打交道就有久了. 每次初始化一个项目时都能看到 django.middlewa ...

  5. 【Python全栈-后端开发】Django进阶之Model操作复习

    Django进阶之Model操作复习 一.字段 AutoField(Field) - int自增列,必须填入参数 primary_key=True BigAutoField(AutoField) - ...

  6. Python开发【Django】:Model操作(二)

    Model操作 1.操作汇总: # 增 # # models.Tb1.objects.create(c1='xx', c2='oo') 增加一条数据,可以接受字典类型数据 **kwargs # obj ...

  7. Django使用普通表单、Form、以及modelForm操作数据库方式总结

    Django使用普通表单.Form.以及modelForm操作数据库主要应用于增删该查的情景下,流程通用如下,只是实现方式不一样: 进入填写表单页面: 在表单页面填写信息,并提交: 表单数据验证 验证 ...

  8. day23 Model 操作,Form 验证以及序列化操作

    Model 操作 1创建数据库表 定制表名:       普通索引:             创建两个普通索引,这样就会生成两个索引文件   联合索引:           为了只生成一个索引文件,才 ...

  9. Django中的分页操作、form校验工具

    批量插入数据 后端: def fenye(request): book_list=[] for i in range(100): book_list.append(models.Book(title= ...

随机推荐

  1. 【朝花夕拾】Android性能篇之(七)Android跨进程通信篇

    前言 只要是面试高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点之一.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Andro ...

  2. QUIC协议原理分析(转)

    之前深入了解了一下HTTP1.1.2.0.SPDY等协议,发现HTTP层怎么优化,始终要面对TCP本身的问题.于是了解到了QUIC,这里分享一篇之前找到的有意义的文章. 原创地址:https://mp ...

  3. 多机同步管理hexo博客

    转载自:https://www.zhihu.com/question/21193762/answer/79109280 一.关于搭建的流程 创建仓库,<your github username& ...

  4. ASP.NET Core 使用 Google 验证码(reCAPTCHA v3)代替传统验证码

    写在前面 友情提示: Google reCAPTCHA(v3下同) 的使用不需要"梯子",但申请账号的时候需要! Google reCAPTCHA 的使用不需要"梯子&q ...

  5. python ddt数据驱动(简化重复代码)

    在接口自动化测试中,往往一个接口的用例需要考虑 正确的.错误的.异常的.边界值等诸多情况,然后你需要写很多个同样代码,参数不同的用例.如果测试接口很多,不但需要写大量的代码,测试数据和代码柔合在一起, ...

  6. Python Ast介绍及应用

    Abstract Syntax Trees即抽象语法树.Ast是python源码到字节码的一种中间产物,借助ast模块可以从语法树的角度分析源码结构.此外,我们不仅可以修改和执行语法树,还可以将Sou ...

  7. Python数据采集——提取页面内容的几种手段

    前言 在我们获取了网页的信息后,往往需要对原始信息进行提取,得到我们想要的数据.对信息的提取方式主要有以下几种:正则表达式.XPath.BeautifulSoup.本篇博客主要总结这三种方式的基本语法 ...

  8. Django-restframework 之权限源码分析

    Django-restframework 之权限源码分析 一 前言 上篇博客分析了 restframework 框架的认证组件的执行了流程并自定义了认证类.这篇博客分析 restframework 的 ...

  9. JFreeChart画图+jsp页面显示实现统计图

    1 开发环境: 1.eclipse(可替换) 2.jfreechart-1.0.19 2 说明: (1) source目录:为 jfreechart的源码目录:不会的主要看这里.因为他的文档是收费的. ...

  10. Android串口通讯

    今天在整一个项目,需要利用串口通讯在网上看了好多人的帖子才稍微整出了一点头绪. 首先串口代码就是利用谷歌自己的api,将java代码放在java/android_serialport_api目录下,如 ...