django是python语言快速实现web服务的大杀器,其开发效率能够很是的高!但由于秉承了语言的灵活性,django框架又太灵活,以致于想实现任何功能都有种“条条大路通罗马”的感受。这么多种选择放在一块儿,如何分出高下?我想此时的场景下就两个标准:一、相同的功能用最少的代码实现(代码少BUG也会少);二、相对最易于理解,从而易于维护和扩展。书归正传,web服务容许用户输入,基本上要靠表单。而django对表单的支持力度很是大,咱们用不着在浏览器端的html文件里写大量<form>代码,再到web端去匹配form里的id/name/value、验证规则,再与持久层数据库比较并作操做。咱们须要完成的工做很是少,能够没有类似的重复代码。有些复杂的场景,会要求一个表单的内容存放到多张表里,本文将经过4个部分,阐述它的实现方法。html
一、django基础表单的功能python
定义一个表单很是简单,继承类django.forms.Form便可,例如:web
这个表单类能够生成HTML形式的form,能够从request.POST中解析form到ProjectForm类实例。怎么作到的呢?数据库
看下django.forms.Form定义:django
注释说得很清楚,Form这个类就是为了实现declarative syntax的,也就是说,继承了Form后,咱们直观的表达ProjectForm里要有一个Field名叫name,不关心其语法实现,而经过Form多继承中的DeclarativeFieldsMetaclass语法糖,将会把name弄到类实例的self.fields里。浏览器
咱们重点关注表单的BaseForm类,它实现了基本的逻辑。截选了一小段对接下来的陈述有意义的代码,作一个简单的注释。并发
因此,基本表单的功能看BaseForm已经足够了。框架
二、从模型建立表单post
django对于MVC中的C与M间的映射是很是体贴的,集中体现中Model模型中(好比模型的权限与用户认证)。那么,一个模型表明着RDS中的一张表,模型的实例表明着关系数据库中的一行,而form如何与一行相对应呢?网站
定义一个模型引伸出的表单很是简单,例如:
在model中告诉django模型是谁,在fields中告诉django须要在表单中建立哪些字段。django会有一个django.db.models.Field到django.forms.Field的转换规则,此时会生成Form。咱们看看ModelForm是什么样的:
相似Form类,ModelFormMetaclass就是语法糖,咱们重点看BaseModelForm类:
因此,对于ModelForm咱们能够传入instance参数初始化表单,能够调用save()方法直接将从html里获得的表单数据持久化到数据库中。而咱们只须要几十行代码就能够完成这么多工做。
三、通用视图
django.views.generic.ListView和django.views.generic.edit下的CreateView, UpdateView, DeleteView都是通用视图。即,咱们又能够经过它们,把不少重复的工做交给django完成,又能够少写不少代码完成一样的功能了。这里仅以CreateView为例说明,由于它相对最复杂,接下来的多ModelForm的提交也是在CreateView上进行的。
通用视图使用时,只须要承继后,再设置model或者form_class便可。好比CreateView就会由django自动的把页面上POST出的form数据解析到model生成的表单(或者form_calss指定的ModelForm类型表单),同时调用表单的save方法将数据添加到模型对应的数据库表中。固然GET请求时会生成空form到页面上。能够看到,除去定义model或者form类外,几行代码就能够搞定这么多事。咱们看看CreateView的继承关系:
简单介绍下CreateView通用视图中每一个父类的做用。
因此,在用CreateView、一个模型、一个模板实现添加一行记录的功能时是多么简单,由于这些父类会自动生成object,渲染到模板,解析form表单,save到数据库中。因此,从模型建立出的表单ModelForm,配合上通用视图后,威力巨大!!
四、多个ModelForm在一个form里提交
终于能够回到本文的主题了。CreateView默认是处理一个Model模型、一个ModelForm表单的,然而,不少时候为了解耦,会把一张表拆成多张表,经过id关联在一块儿。在django的模型中就体现为ForeignKey、ManyToManyField或者OneToOneField。而在业务逻辑上,须要体现为一张表单,对应着数据库里的多张表。
例如,咱们但愿录入合同,其中合同Model中还有地址Model和项目Model,而项目Model中又有地址Model,等等。
固然,咱们有不少种实现的方案,可是,前面三部分说了那么多,不是浪费口水的。咱们已经有了通用视图+ModelForm这样的利器,难道还须要手动去写Form表单?咱们已经习惯了在Model里定义好类型和有点注释做用还能当label的verbose_name,还须要在forms.Form里再来一遍?还须要在视图中写这么通用的逻辑代码吗?固然不用。
inlineformset_factory是一种方案,但它限制太多,并且有些晦涩,我我的感受是不太好用的。
那么,从第1部分我介绍的Form里的prefix,以及第3部分里类图中的ProcessFormView容许重定义form_valid,以及第2部分中ModelForm的save方法的行为控制,解决方案已经一目了然了。
拿上面提到的例子来讲,咱们建立合同时,指明了项目,包括项目地址和合同签定地址,这涉及到三张表和四条记录(地址表有两条)。
咱们三张表的模型以下:
接着,定义ModelForm表单,这很是简单:
再写视图,这里要重写2个方法:
最后写模板:
至此,咱们能够只用几十行代码就完成复杂的功能,代码逻辑也清晰可控。
从这篇文章里也能够看得出,django实在是快速开发网站的必备神器!固然,快速不表明不可以支撑大并发的应用,instagram这个很火的服务就是用django写的。因为python和django过于灵活,都将要求django的开发者们惟有更资深才能写出生产环境下的服务。