参考源出处:http://blog.csdn.net/fgf00/article/details/54629502

1. 搭建环境请参考:http://www.cnblogs.com/momo8238/p/7508677.html

二、Form操作

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

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

1-fields :验证(肯定会用的)

2-widgets:生成HTML(有时候用,有时候可以不用)

  2.1一般新url方式操作用widgets,因为生成url不是关键的,可以保留上一次提交的数据

  2.2Ajax请求的时候,可以不用它生成html

1.1、Form操作动态Select数据

urls.py

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

views.py

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

forms.py

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

models.py

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

index.html

  1. <body>
  2. <p>{{ obj.user }}</p>
  3. <p>{{ obj.pwd }}</p>
  4. <p>{{ obj.user_type }}</p>
  5. <p>{{ obj.user_type2 }}</p>
  6. </body>

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

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

__init__里面写的属于对象。

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

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

views.py

  1. def index(request):
  2.  
  3. from cmdb.forms import UserInfoForm
  4. from cmdb import models
  5.  
  6. obj = UserInfoForm()
  7. obj.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
  8.  
  9. return render(request, 'index.html', {'obj':obj})

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

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

forms.py

  1. from django import forms
  2. from django.forms import widgets, fields
  3. from cmdb import models
  4.  
  5. class UserInfoForm(forms.Form):
  6. user = fields.CharField(
  7. required=False,
  8. widget=widgets.Textarea(attrs={'class':'c1'})
  9. )
  10. pwd = fields.CharField(
  11. max_length=12,
  12. widget=widgets.PasswordInput(attrs={'class':'c1'})
  13. )
  14. user_type = fields.ChoiceField(
  15. # choices=[(1,'普通用户'),(2,'超级用户')], # 手动填写
  16. choices=[], # 构造方法里取,这里只定义就可以了,不需要在获取一次。
  17. widget=widgets.Select
  18. )
  19.  
  20. #### 另外一种写法 方式 ####
  21. user_type2 = fields.ChoiceField(
  22. widget=widgets.Select(choices=[])
  23. )
  24.  
  25. def __init__(self, *args, **kwargs):
  26. super(UserInfoForm,self).__init__(*args, **kwargs)
  27.  
  28. self.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
  29. #### 另外一种写法 方式 ####
  30. self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id','name')

1.2、Form操作动态Select数据

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

django 里自动实现的,看user_type3

  1. from django import forms
  2. from django.forms import widgets, fields
  3. from django.forms.models import ModelChoiceField
  4. from cmdb import models
  5.  
  6. class UserInfoForm(forms.Form):
  7. user = fields.CharField(
  8. required=False,
  9. widget=widgets.Textarea(attrs={'class':'c1'})
  10. )
  11. pwd = fields.CharField(
  12. max_length=12,
  13. widget=widgets.PasswordInput(attrs={'class':'c1'})
  14. )
  15. user_type = fields.ChoiceField(
  16. choices=[],
  17. widget=widgets.Select
  18. )
  19. user_type2 = fields.ChoiceField(
  20. widget=widgets.Select(choices=[])
  21. )
  22. user_type3 = ModelChoiceField(
  23. queryset=models.UserType.objects.all()
  24. )
  25.  
  26. def __init__(self, *args, **kwargs):
  27. super(UserInfoForm,self).__init__(*args, **kwargs)
  28.  
  29. self.fields['user_type'].choices = models.UserType.objects.values_list('id','name')
  30. self.fields['user_type2'].widget.choices = models.UserType.objects.values_list('id','name')

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

  1. class UserType(models.Model):
  2. name = models.CharField(max_length=32)
  3.  
  4. def __str__(self):
  5. return self.name

ModelChoiceField 参数

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

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

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

初始化操作

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

views.py

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

数据验证

views.py

  1. def index(request):
  2.  
  3. from cmdb.forms import UserInfoForm
  4.  
  5. if request.method == 'GET':
  6. obj = UserInfoForm({'user':'fgf','user_type':'2'})
  7. return render(request, 'index.html', {'obj':obj})
  8. elif request.method == 'POST':
  9. obj = UserInfoForm(request.POST, request.FILES) # request.FILES:接收文件
  10. obj.is_valid() # 数据验证

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

注册数据验证示例

forms.py

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

登录数据验证示例

forms.py

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

验证顺序

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

form循环,

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

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

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

验证完成后

views.py(伪代码)

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

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

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

Ajax 提交数据,进行验证

urls.py

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

views.py

  1. from django import forms
  2. from django.forms import widgets, fields
  3. class LoginForm(forms.Form):
  4. username = fields.CharField()
  5. password = fields.CharField(
  6. max_length=64,
  7. min_length=12
  8. )
  9.  
  10. def login(request):
  11. import json
  12. res = {'status':True, 'error':None, 'data': None}
  13. if request.method == "GET":
  14. return render(request,"login.html")
  15. elif request.method == "POST":
  16. obj = LoginForm(request.POST)
  17. if obj.is_valid():
  18. print(obj.cleand_data)
  19. else:
  20. # print(obj.errors, type(obj.errors))
  21. res['error'] = obj.errors.as_json() # 转为json格式
  22. return HttpResponse(json.dumps(res))

login.html

  1. <body>
  2. <form id="fm">
  3. {% csrf_token %}
  4. <p><input type="text" name="username" /></p>
  5. <p><input type="password" name="password" /></p>
  6. <a id="submit">ajax提交</a>
  7. </form>
  8. <script src="/static/jquery-1.12.4.js"></script>
  9. <script>
  10. // 页面框架加载完自动执行
  11. $('#submit').click(function(){
  12. $.ajax({
  13. url:'/login.html',
  14. type:'POST',
  15. data:$('#fm').serialize(),
  16. success:function(arg){
  17. console.log(arg);
  18. arg = JSON.parse(arg); // 转为字典
  19. console.log(arg);
  20. },
  21. error: function(){
  22.  
  23. }
  24. })
  25. })
  26. </script>
  27. </body>

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

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

views.py

  1. from django import forms
  2. from django.forms import widgets, fields
  3. class LoginForm(forms.Form):
  4. username = fields.CharField()
  5. password = fields.CharField(
  6. max_length=64,
  7. min_length=12
  8. )
  9.  
  10. # 序列化,转换为指定数据类型
  11. import json
  12. from django.core.exceptions import ValidationError
  13. class JsonCustomEncoder(json.JSONEncoder):
  14. def default(self, field):
  15. if isinstance(field, ValidationError):
  16. return {'code':field.code, 'messages': field.messages}
  17. else:
  18. return json.JSONEncoder.default(self, field)
  19.  
  20. def login(request):
  21. res = {'status':True, 'error':None, 'data': None}
  22. if request.method == "GET":
  23. return render(request,"login.html")
  24. elif request.method == "POST":
  25. obj = LoginForm(request.POST)
  26. if obj.is_valid():
  27. print(obj.cleand_data)
  28. else:
  29. # print(obj.errors, type(obj.errors))
  30. # res['error'] = obj.errors.as_json() # 转为json格式
  31. print(type(obj.errors.as_data()))
  32. for k,v in obj.errors.as_data().items():
  33. print(k,v) # 这里v是ValidationError类型,不能序列化
  34. res['error'] = obj.errors.as_data()
  35. result = json.dumps(res, cls=JsonCustomEncoder)
  36. return HttpResponse(json.dumps(result))

4、Django 序列化操作

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

ErrorDict自定义JSONEncoder

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

  1. import json
  2. from datetime import date
  3. from datetime import datetime
  4.  
  5. class JsonCustomEncoder(json.JSONEncoder):
  6.  
  7. def default(self, field):
  8.  
  9. if isinstance(field, datetime):
  10. return o.strftime('%Y-%m-%d %H:%M:%S')
  11. elif isinstance(field, date):
  12. return o.strftime('%Y-%m-%d') # 转成字符串类型
  13. else:
  14. return json.JSONEncoder.default(self, field)
  15.  
  16. v = {'k':'', "k1":datetime.datetime.now()}
  17. ds = json.dumps(v, cls=JsonCustomEncoder)

QuerySet 第一种序列化方式

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

  1. from django.core import serializers
  2.  
  3. v = models.tb.objects.all()
  4. data = serializers.serialize("json", v)

QuerySet 第二种序列化方式

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

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

Day23-Model操作,Form操作和序列化操作的更多相关文章

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

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

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

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

  3. Django(八)下:Model操作和Form操作、序列化操作

    二.Form操作 一般会创建forms.py文件,单独存放form模块. Form 专门做数据验证,而且非常强大.有以下两个插件: fields :验证(肯定会用的) widgets:生成HTML(有 ...

  4. Asp.Net Core 2.0 项目实战(8)Core下缓存操作、序列化操作、JSON操作等Helper集合类

    本文目录 1.  前沿 2.CacheHelper基于Microsoft.Extensions.Caching.Memory封装 3.XmlHelper快速操作xml文档 4.Serializatio ...

  5. DRF之简介以及序列化操作

    1. Web应用模式. 在开发Web应用中,有两种应用模式: 前后端不分离 2.前后端分离 2. api接口 为了在团队内部形成共识.防止个人习惯差异引起的混乱,我们需要找到一种大家都觉得很好的接口实 ...

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

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

  7. django之djangorestframework序列化操作

    只介绍序列化操作:serializers.ModelSerializer 与 serializers.Serializer 使用序列化的目的:将数据序列化成  JSON 对象 当页面上需要动态加载内容 ...

  8. Python json.dumps 特殊数据类型的自定义序列化操作

    场景描述: Python标准库中的json模块,集成了将数据序列化处理的功能:在使用json.dumps()方法序列化数据时候,如果目标数据中存在datetime数据类型,执行操作时, 会抛出异常:T ...

  9. C# XML序列化操作菜单

    鉴于之前写的一篇博文没使用XML序列化来操作菜单,而且发现那还有一个问题,就是在XML菜单的某个菜单节点前加上一些注释代码的就不能读取,现在使用XML序列化后可以很方便的读取,故在此写一写.   XM ...

随机推荐

  1. ansible-playbook如何判断并中断执行

    - fail: msg="Bailing out. this play requires 'bar'"       when: bar is not defined 我的需求是当某 ...

  2. 同步IO和异步IO的区别

    首先一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作,同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO.非阻塞IO.IO服用 ...

  3. 20155325 Exp3 免杀原理与实践

    基础问题回答 杀软是如何检测出恶意代码的? 1.1 基于特征码的检测 1.1.1 特征库举例-Snort 1.2 启发式恶意软件检测 1.3 基于行为的恶意软件检测 免杀是做什么? 一般是对恶意软件做 ...

  4. js实现60秒倒计时效果(使用了jQuery)

    今天碰到要实现一个类似那种短信验证码60秒倒计时的需求,好久不写js,有点手生.把代码记录下,方便后续查阅. 这里我用了jQuey,毕竟写起来简洁点.下面直接看效果和代码. 一.效果          ...

  5. C++中前置声明介绍

    前置声明是指对类.函数.模板或者结构体进行声明,仅仅是声明,不包含相关具体的定义.在很多场合我们可以用前置声明来代替#include语句. 类的前置声明只是告诉编译器这是一个类型,但无法告知类型的大小 ...

  6. 51nod 小朋友的笑话

    链接 分析: 每次操作把以前没有出现这个数的设为1,有这个数的设为0.首先将当前区间设为1,考虑有set维护这个颜色出现的区间,然后把所有与当前区间相交的拿出来,修改为0. 复杂度?每次操作的线段只会 ...

  7. Selenium-Css Selector使用方法

    什么是Css Selector? Css Selector定位实际就是HTML的Css选择器的标签定位 工具 Css Selector的练习建议大家安装火狐浏览器后,下载插件,FireFinder 或 ...

  8. P4292 [WC2010]重建计划

    无脑上二分+淀粉质完事了 每个子树算的时候把儿子按照最长路径从小到大依次做,和前面的单调队列算一波,每个儿子的复杂度不超过这个子树大小 // luogu-judger-enable-o2 #inclu ...

  9. libgdx学习记录7——Ui

    libgdx中的UI设计主要通过其对应的Style类进行实现,也可以通过skin实现.如果没有编辑好的skin文件,可以创建一个默认的skin,再添加已经设计好的style类即可,然后在需要使用的地方 ...

  10. MOSFET简介以及PMOS和NMOS的差异

    最近在工作中,一直在调试关于MOSFET的电路.在设计过程中发现了PMOS和NMOS的差异,在此记录. 一. MOSFET简介 MOSFET (metal-oxide-semiconductor fi ...