Django 中 ModelForm 的使用
- 定义 ModelForm
- 定制 ModelForm
- 值得一提的一些 Field 转化
- 初始化 ModelForm
- 校验 ModelForm
- 储存 ModelForm 对象
- 定义一个 Form 来新建、更新实例
什么是 ModelForm
- Model 在 Django 对应数据库模型
- 一个 Model 拥有多个 Model.Field
- Form 在 Django 对应表单
- 一个 Form 拥有多个 Form.Field
ModelForm 即基于 Model 的 Form,把 Model 中的 Field 根据下图中的映射关系自动转化为 Form 中的 Field。
为什么使用 ModelForm
利用 Model 生成 Form,提高 Model 复用性
如何使用 ModelForm
定义 ModelForm
举一个书籍管理例子
# Model class Article(models.Model): |
这个 Model 中定义了两个字段
- title
- 储存书籍标题
- 数据类型是 char
- 最大长度 20
- 数据库唯一值限制,即不能储存两本相同标题的书
- author
- 储存书籍的作者
- 数据类型是外键,指向 Model
Author
下面我们用 ModelForm 构建表单
# ModelForm class ArticleForm(forms.ModelForm): |
和下面手动构建表单的代码等效
class ArticleForm(forms.Form): |
定制 ModelForm
很多情况下自动生成的 ModelForm 并不能满足设计要求,下面我们来讲一下如何定制
定制有两种方式
- Meta
- 使用 Model 转化的时候自定义转化规则
- 自定义字段
- 定义额外的 Field,会覆盖 Model 自动生成的 Field
Meta
ModelForm 是通过 Meta 来把 Model.Field 自动转化为 Form.Field 的,其中涉及到几步转化
- validators 不变
- 添加 widget 属性
- 即前端的渲染方式
- 修改 Model 包含的字段
- 通过 fields 来拿指定字段
- 通过 exclude 来排除指定字段
- 修改错误信息
我们通过下面的例子来看一下如何通过 Meta 来定制 ModelForm
class ArticleForm(forms.ModelForm):
class Meta:
|
Meta 的缺点是不能修改字段的 validators,如果需要自定义 validators,需要在 Meta 外部重新定义一个同名 Field 来覆盖自动生成的 Field
在 Form 中另外定义 Field
这是 Form 中定义 Field 的通用方法,在 ModelForm 中它有两个作用
- 补充 Model 没有的 Field 到 Form
- 覆盖 Model 中的同名 Field 定义
且看下面的例子,Article 中已经包含了 title 字段,我们在 ModelForm 中重新定义了它,把 CharField 改为了 ChoiceField,并且自定义了 validators。
覆盖 title 的时候,把 title 从 Meta 中 exclude 掉是可选的,去不去掉的区别在于,你是否需要它为你校验
unique=True这个数据库级限制。
在这里我们需要校验,因为 ModelForm 校验通过后我需要把它存入数据库,如果这里没有校验的话,碰到同标题的书数据库就会在储存时报错,我们希望把这步校验放在 ModelForm 的校验中,而不是在通过校验后再用try... catch...来捕获它。
class ArticleForm(forms.ModelForm): |
值得一提的一些 Field 转化
AutoField
该 Field 不会出现在 ModelForm 表单中。
所有
editable=False的 Field 都不会出现在 ModelForm 中。
BooleanField
由于表单提交时统一识别为 string,而 BooleanField 是用 python 中的 bool 来判断的,所以只要传了任意非空值,BooleanField 都会当做 True 来处理,而如果传了空值,由于 forms.Field 默认属性是 required=True,会校验失败,所以如果你需要一个可以填 False 的 Field,那么你需要在 Form 中手动设置这个 Field 的 required=False。
ForeignKey
ForeignKey 自动转化为 ModelChoiceField,用下拉选项菜单渲染,默认渲染出来的选项显示为对应 Field 的 __str__,提交的值为对应 Field 的 id,这些都可以定制。
在后端接收提交的时候会自动在对应的 Model 中用 id 去找,如果没找到则抛出 ValidationError。
ManyToManyField
ManyToManyField 自动转化为 ModelMultipleChoiceField,用多选框渲染,同样默认渲染出来的选项显示为对应 Field 的 __str__,提交的值为对应 Field 的 id 值。
比如有个叫 group 的 ManyToManyField,选中了 'finance' 'develop' 这两个选项,他们的 id 分别为 1 和 2,那么世界上提交的表单 QueryString 就是 group=1&group=2
初始化 ModelForm
form = ArticleForm(request.POST) |
article = Article.objects.get(pk=1) |
- instance
- 给 ModelForm 初始化 Model 实例,后续的操作都作用在这个实例上
- initial
- 给 ModelForm 初始值
- 如果和 instance 同时被定义,同名 field 的值覆盖 instance 中的值
数据加载的先后顺序为 instance, initial, request.POST
校验 ModelForm
Form 只会检查内部定义过的 Field,request.POST 中其余 keyword 都会被无视和过滤掉,即不会出现在返回的 cleaned_data 中。
form = ArticleForm(request.POST) # 校验表单 |
is_valid() 会调用 full_clean() 来对表单进行全面校验,它又分成三步(定义在基类 Form 中)
- 根据每个 Field 注册的 validators 做单个 Field 的校验 (比如 title 字段就会校验是否超出最大允许长度 20) 其中在
Field.clean()执行过后提供了钩子clean_[field_name],可以自定义该 function 来注册自己的校验方法。 - 根据 Form 定义的 Field 之间的依赖关系做整个表单的校验,钩子为
clean(),默认为空。 - 自定义校验通过后的表单处理,钩子为
_post_clean()- 这一步中,ModelForm 做了一些额外的检验:如果定义在 Meta 中的 Field 有
unique=True这个限制,那么 ModelForm 会按照现有数据库中的数据对其校验,看这个 Field 的值是否已存在,如果已存在,则抛出一个IntegrityError。实际操作中如果强制不校验 unique 的话,可以把该字段从 Meta 中移除,在 ModelForm 中重新定义该字段。
- 这一步中,ModelForm 做了一些额外的检验:如果定义在 Meta 中的 Field 有
储存 ModelForm 对象
调用 save() 的时候可以传入 commit=False 来避免立即储存,从而通过后续的修改或补充来得到完整的 Model 实例后再储存到数据库。
如果初始化的时候传入了 instance,那么调用 save() 的时候会用 ModelForm 中定义过的字段值覆盖绑定实例的相应字段,并写入数据库。
save() 同样会帮你储存 ManyToManyField,如果 save 时使用了 commit=False,那么 ManyToManyField 的储存需要等该条目存入数据库之后手动调用 ModelForm 的 save_m2m() 方法。
定义一个 Form 来新建、更新实例
通常的步骤分为如下几步
- 检测该对象是否已在数据库
- 如果已存在,那么手动获取该实例,然后更改相关 field 内容,最后使用
update()方法保存到数据库 - 如果不存在,新建一个 Model 实例并修改至完整的 Model,调用
save()方法保存到数据库
- 如果已存在,那么手动获取该实例,然后更改相关 field 内容,最后使用
写成代码的话是这样子
f = AuthorForm(request.POST) if f.is_valid(): |
太麻烦了!!其实 Django 中已经有 update_or_create 方法已经实现了上述所有功能,可以避免这个 try ... except ... 判断实例是否已存在,我们来看这个例子
# forms.py class AuthorAddForm(forms.ModelForm): |
# views.py class AuthorsView(LoginRequiredMixin, TemplateView): |
其中 update_or_create 通过检测所有非 defaults 的字段,在上述例子中就是 id=form.cleaned_data['id'] 一项是否已存在于数据库而判断是用 update() 还是 create(),而不论是 update() 还是 create(),都会使用 cleaned_data 作为数据源来写入数据库。
Django 中 ModelForm 的使用的更多相关文章
- Django中ModelForm应用
Django中ModelForm的应用 在传统中Form提交的POST的数据在服务器端获取时将不得不一一获取并验证数据的可靠性,但是使用django提供的Form时可简化该过程并提供相应的验证,同时D ...
- Django中Model-Form验证
Django中Model-Form验证 class UserType(models.Model): caption=models.CharField(max_length=32) class User ...
- django中ModelForm save方法 以及快速生成空表单或包含数据的表单 包含错误信息
django中ModelForm学习系列一~save方法 Model代码 from django.db import models # Create your models here. class P ...
- Django中ModelForm详解
1.ModelForm组件介绍:这个组件的功能就是把model和form组合起来 2.ModelForm的使用 1.首先需要导入ModelForm from django.forms import M ...
- django中ModelForm解决多表单组合显示问题
一.多表单组合显示问题 在项目中用ModelForm生成页面时 当有多表单组合显示时,会显示全部的关联表单数据. 而在实际项目中可能会出现只想让用户选择部分数据,这时候这样的显示就有问题. 二.问题解 ...
- Django中使用ModelForm实现Admin功能
接上一篇<Django中使用Bootstrap> ModelForm 可以将数据库中的信息展示在一个表中,因此我们在查询数据库信息时可以使用ModelForm在前端展示查询到的信息. 在上 ...
- Django中的ModelForm与Form
django表单系统中,所有的表单类都作为django.forms.Form的子类创建,包括ModelForm. 关于django中的表单系统有两种: 基于django.forms.Form 基于dj ...
- Django中的Form表单
Django中已经定义好了form类,可以很容易的使用Django生成一个表单. 一.利用Django生成一个表单: 1.在应用下创建一个forms文件,用于存放form表单.然后在forms中实例华 ...
- Django之modelform组件
一.简介与基本使用 简介:django中的modelform组件同时具有model和form作用,但是耦合度比较高,当项目需要拆分时候就比较困难了,所以在使用modelform时候需要先考虑项目的扩展 ...
随机推荐
- ES数据架构与关系数据库Mysql
ES数据架构的主要概念(与关系数据库Mysql对比) MySQL ElasticSearch Database Index Table Type Row Document Column Field S ...
- idea 下获取路径下文件的方法
想读取resouce/temp下的test.txt文件.方式一:File sourceFile = ResourceUtils.getFile("classpath:temp/test.tx ...
- PowerDesigner 生成SQL Server 注释脚本
--生成数据表的注释EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=[%R%?[N]]%.q:COMMENT% , @l ...
- Spring 静态代理和动态代理
现在我们来模拟一下,某位学生去考试. 假设他(小明)正常的考试. 运行结果: 结果: 突然某一天,他睡过头了,来不急去考试,所有他打算叫另一个人(Cheater)去代替他考试. 运行结果 ...
- python进阶ing——创建第一个Tornado应用
python进阶ing——创建第一个Tornado应用 分类: Python2013-06-02 23:02 1725人阅读 评论(2) 收藏 举报 pythonTornado 每天在群里跟很多群友讨 ...
- Python CGI编程Ⅲ
GET和POST方法 浏览器客户端通过两种方法向服务器传递https://www.xuanhe.net/信息,这两种方法就是 GET 方法和 POST 方法. 使用GET方法传输数据 GET方法发送编 ...
- linux运维、架构之路-K8s滚动更新及回滚
一.滚动更新 应用程序一次只更新一小部分副本,更新成功后,再更新更多的副本,最终完成所有副本的更新. 滚动更新的优点:零停机,整个更新过程始终有副本在运行,从而保证了业务的连续性. 1. ...
- 【杂题】[ARC070F] Honest Or Unkind【交互】
Description 这是一道交互题 有A+B个人,编号从0~A+B-1,其中有A个人是诚实的,B个人是居心叵测的. 你想知道每个人是诚实的还是居心叵测的. 询问可以用二元组(i,j)表示,代表问编 ...
- mv:移动文件或改名
mv 命令(move 的缩写),既可以在不同的目录之间移动文件或目录,也可以对文件和目录进行重命名.该命令的基本格式如下: mv [选项] 源文件 目标文件 选项: -f:强制覆盖,如果目标文件已经存 ...
- HDU 2829 [Lawrence] DP斜率优化
解题思路 首先肯定是考虑如何快速求出一段铁路的价值. \[ \sum_{i=1}^k \sum_{j=1, j\neq i}^kA[i]A[j]=(\sum_{i=1}^kA[i])^2-\sum_{ ...