在Django同1个页面中的多表单处理详解


Posted in Python onJanuary 25, 2017

快速上手Django实现项目

近期公司在做1个海淘的项目,APP为pylot。由于时间比较赶,加上隔壁那哥们不在,只能自己挑大梁了。结果,当项目做出来之后,被领导狠狠的批了一顿,说怎么用django写,你能解决Django的内存问题吗,你能解决并发的问题吗?Django那么重。

然后我只好回答说,正是因为它重,所以人家拿来写大型项目。虽然这里不是为了上面这2个问题的,而是来说下如何快速开发原型的问题。

对于Django这样基于模型的Web框架,实话说真的解决了很多繁琐的工作。由于它1个模型对应1张表,因此只要很短暂的时间就把原型给弄完了。实际上,我用Django主要是不用被页面浪费我的时间,这样我就可以专心写API那方面了。

结果,公司这个项目除了自己可以看到外,还要实现1个B端的需求,而我此时的后台功能已经完成了,这可以如何是好。而区别在于只能让注册的用户只能看到属于它自己的订单,而其他不变。

于是上官方文档看了下表单的教程,看到1个ModelForm的玩意,通过它可以将后台的表单直接渲染出来,而后在ModelForm类中通过instance关键字可以将对应模型直接渲染出来,这样花了1个星期的时间就把API、B端和公司的后台完成了,效率还算比较高。

下面说下如何通过Django快速实现项目:

  1. 实际上分解问题很关键,把问题按等级划分有助于加快开发速度
  2. 把不怎么会写的代码先跳过,使用繁琐的方式先写上去,后面再用其内建的方式来替换
  3. 不要紧张,一定要保持淡定,不然你会发现你完全写不出代码
  4. 不要看官方文档,因为写的??掠帜颜业街氐?/li>
  5. 带着问题在网上搜索答案,如果某个方式不行就换种思路去做,比如要实现1个多对多的关系的HTML组件,直接找第3方插件而不是看文档实现

相信如何能做到以上几点,才能把django的效率发挥出来。下面来看看本文的详细介绍吧。

Django同1个页面中的多表单处理

关于在同1个页面多个表单提交的问题,实际上是项目中遇到的1个小问题。关于这个问题,主要有2个需要解决的问题:

  1. 多个表单的渲染问题
  2. 多个表单提交时外键的处理问题

下面我们分别进行说明。

当时在建模的时候使用了类似如下的方式:

from django.db import models 

class Store(models.Model): 
 name = models.CharField('名称', max_length=20) 
 first = models.FloatField('首重') 
 additional = models.FloatField('次重') 
 img = models.ImageField('图片', upload_to='store/1') 

class Depot(models.Model): 
 s_name = models.ForeignKey(Store, verbose_name='仓库') 
 src = models.CharField('始发地', max_length=20) 
 dest = models.CharField('目的地', max_length=20) 
 days = models.PositiveSmallIntegerField('需要的天数') 

class Address(models.Model): 
 s_name = models.ForeignKey(Store, verbose_name='仓库') 
 country = models.CharField('国家', max_length=20) 
 state = models.CharField('省份', max_length=10) 
 city = models.CharField('城市', max_length=10) 
 description = models.TextField('描述', blank=True)

在这里,1个仓库的数据主要由3个表组成,分别为它的一些基础信息,可以配送的范围、天数及其他一些附加信息组成。然后其页面如下所示:

在Django同1个页面中的多表单处理详解

多表单渲染

而公司的需求就是我们要在商户端上让客户在创建仓库时填写上述的内容,由于我比较懒,而公司给出的时间也不是很充裕,于是直接使用ModelForm来实现,而不需要一一的创建表单了。换句话说,我们要将多个模型表在同1个页面中渲染出来,对于这样的问题,主要有4种解决的方案:

  1. 在1个form组件中使用多个模型表单类
  2. 使用django提供的modelform_factory来解决
  3. 使用第3方插件django-betterforms或django-multipleformwizard这样的插件
  4. 使用元类,然后继承BaseForm进行表单的重写。

这里我们使用第1种解决方案来实现多个表单渲染的问题。

这里我们在forms模块下新建3个模型表单类:

from django.forms import ModelForm 
from models import Store, Address, Depot 

class StoreForm(ModelForm): 
 class Meta: 
 model = Store 
 fields = '__all__' 

class AddressForm(ModelForm): 
 class Meta: 
 model = Address 
 exclude = ['s_name'] 

class DepotForm(ModelForm): 
 class Meta: 
 model = Depot 
 exclude = ['s_name']

然后在视图中引入这3个表单:

from django.shortcuts import render_to_response, HttpResponseRedirect 
from django.template import RequestContext 
from forms import StoreForm, AddressForm, DepotForm 

def store_add(req): 
 if req.method == 'POST': 
 ... 
 else: 
 sf = StoreForm() 
 af = AddressForm() 
 df = DepotForm() 
 return render_to_response('store_add.html', { 
 'sf': sf, 'af': af, 'df': df, 
 }, context_instance=RequestContext(req))

默认情况下,我们先将对应的表单渲染出来先。在这里我们往模板中输出了多个变量,然后在模板中手动进行如下的处理:

<form action="" method='post' enctype='multipart/form-data'> 
 {% csrf_token %} 
 {{ sf.as_p }} 
 {{ df.as_p }} 
 {{ af.as_p }} 
 <input type="submit" value = "添加" /> 
</form>

在这里,我们在1个表单中输出多个表单,其页面如下所示:

在Django同1个页面中的多表单处理详解

可以看到其效果与后台的页面相差不是很大,只是没有对应的样式而已。

多表单提交外键处理

接着我们需要处理多个表单提交时的处理问题。

def store_add(req): 
 if req.method == 'POST': 
 sf = StoreForm(req.POST, req.FILES) 
 af = AddressForm(req.POST) 
 df = DepotForm(req.POST) 
 if sf.is_valid() and af.is_valid() and df.is_valid(): 
 sf.save() 
 df.save() 
 af.save() 
 return HttpResponseRedirect('store') 
 ...

在这里我们直接对这3个表单进行保存,结果出现了这样1个错误。

NOT NULL constraint failed: app_depot.s_name_id

由于我们使用了1个外键进行了约束,而使用上述的方式会导致数据表中的s_name_id的字段数值为NULL,从而导致了错误。而上述的方式时直接就提交给数据库了,导致后面的外键无法被满足。

为了解决这个问题,我们采用延迟提交给数据库的方式:

def store_add(req): 
 if req.method == 'POST': 
 ... 
 if sf.is_valid() and af.is_valid() and df.is_valid(): 
 form = sf.save(commit=False) 
 sf.save() 
 dform = df.save(commit=False) 
 dform.s_name = form 
 dform.save() 
 aform = af.save(commit=False) 
 aform.s_name = form 
 aform.save() 
 return HttpResponseRedirect('store') 
 else: 
 ...

在这里,我们先让第1张表先不提交,将其保存为1个变量form中。而第2个张表也先不提交,我们将其实例的s_name修改为之前的第1张表返回的结果,然后再进行保存。这样我们就实现了多张表的依赖导致的问题了。最后我们使用重定向的方式将成功添加后的页面跳转到该商户的仓库列表中。

其跳转后的页面如下所示:

在Django同1个页面中的多表单处理详解

这样我们就解决了在1个页面提交多个表单的问题。实际关于Django在1个页面提交多个表单的问题,实际上问题不是很多,只要解决了渲染和提交时处理的问题,实际这个问题就迎刃而解了。重要的是如何拆分问题和解决问题的思路。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Python 相关文章推荐
Python中super关键字用法实例分析
May 28 Python
分享一个可以生成各种进制格式IP的小工具实例代码
Jul 28 Python
Python3.4实现从HTTP代理网站批量获取代理并筛选的方法示例
Sep 26 Python
浅谈python中的正则表达式(re模块)
Oct 17 Python
利用信号如何监控Django模型对象字段值的变化详解
Nov 27 Python
详解Python判定IP地址合法性的三种方法
Mar 06 Python
python实现人脸识别经典算法(一) 特征脸法
Mar 13 Python
Python中的几种矩阵乘法(小结)
Jul 10 Python
Pytorch 之修改Tensor部分值方式
Dec 27 Python
打包PyQt5应用时的注意事项
Feb 14 Python
python实现俄罗斯方块小游戏
Apr 24 Python
python-jwt用户认证食用教学的实现方法
Jan 19 Python
Python heapq使用详解及实例代码
Jan 25 #Python
python3+PyQt5实现使用剪贴板做复制与粘帖示例
Jan 24 #Python
Python调用C++程序的方法详解
Jan 24 #Python
python中import学习备忘笔记
Jan 24 #Python
用python实现简单EXCEL数据统计的实例
Jan 24 #Python
Python如何import文件夹下的文件(实现方法)
Jan 24 #Python
利用Python脚本实现ping百度和google的方法
Jan 24 #Python
You might like
预告映像公开!第1章续篇剧场版动画《Princess Principal Crown Handler》4月10日上映!
2020/03/06 日漫
Zend Framework入门知识点小结
2016/03/19 PHP
CI框架封装的常用图像处理方法(缩略图,水印,旋转,上传等)
2016/11/22 PHP
PHP对称加密算法(DES/AES)类的实现代码
2017/11/14 PHP
addEventListener()第三个参数useCapture (Boolean)详细解析
2013/11/07 Javascript
javascript中数组的concat()方法使用介绍
2013/12/18 Javascript
用JS在浏览器中创建下载文件
2014/03/05 Javascript
Node.js(安装,启动,测试)
2014/06/09 Javascript
html文本框提示效果的示例代码
2014/06/28 Javascript
javascript将异步校验表单改写为同步表单
2015/01/27 Javascript
Jquery实现仿腾讯娱乐频道焦点图(幻灯片)特效
2015/03/06 Javascript
JavaScript中的fontsize()方法使用详解
2015/06/08 Javascript
JavaScript使用FileSystemObject对象写入文本文件内容的方法
2015/08/05 Javascript
详解JavaScript中数组和字符串的lastIndexOf()方法使用
2016/03/13 Javascript
关于javascript中限定时间内防止按钮重复点击的思路详解
2016/08/16 Javascript
Angular在一个页面中使用两个ng-app的方法(二)
2017/02/20 Javascript
详解webpack和webpack-simple中如何引入css文件
2017/06/28 Javascript
Vuejs开发环境搭建及热更新【推荐】
2018/09/07 Javascript
JavaScript内置对象math,global功能与用法实例分析
2019/06/10 Javascript
vue+canvas实现拼图小游戏
2020/09/18 Javascript
vue切换菜单取消未完成接口请求的案例
2020/11/13 Javascript
基于python socketserver框架全面解析
2017/09/21 Python
详解python中Numpy的属性与创建矩阵
2018/09/10 Python
Anaconda配置pytorch-gpu虚拟环境的图文教程
2020/04/16 Python
使用CSS3来绘制一个月食图案
2015/07/18 HTML / CSS
HTML5+Canvas+CSS3实现齐天大圣孙悟空腾云驾雾效果
2016/04/26 HTML / CSS
HTML5通用接口详解
2016/06/12 HTML / CSS
阿根廷票务网站:StubHub阿根廷
2018/04/13 全球购物
国际奢侈品品牌童装购物网站:Designer Childrenswear
2019/05/08 全球购物
土木工程毕业生自荐信
2013/11/12 职场文书
小学生期末评语
2014/04/21 职场文书
课程设计的心得体会
2014/09/03 职场文书
教师节倡议书2015
2015/04/27 职场文书
Spring Boot 排除某个类加载注入IOC的操作
2021/08/02 Java/Android
《帝国时代4》赛季预告 新增内容编译器可创造地图
2022/04/03 其他游戏
聊聊配置 Nginx 访问与错误日志的问题
2022/05/25 Servers