在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高效编程技巧
Jan 07 Python
Python中使用PIPE操作Linux管道
Feb 04 Python
深入讲解Python函数中参数的使用及默认参数的陷阱
Mar 13 Python
浅谈Python 中整型对象的存储问题
May 16 Python
Python 十六进制整数与ASCii编码字符串相互转换方法
Jul 09 Python
python实现自动登录后台管理系统
Oct 18 Python
python中dir()与__dict__属性的区别浅析
Dec 10 Python
Python GUI学习之登录系统界面篇
Aug 21 Python
如何使用repr调试python程序
Feb 28 Python
解决Django no such table: django_session的问题
Apr 07 Python
深入了解Python 变量作用域
Jul 24 Python
Django model重写save方法及update踩坑详解
Jul 27 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
PHP4 与 MySQL 数据库操作函数详解
2006/12/06 PHP
PHP实现利用MySQL保存session的方法
2014/08/23 PHP
PHP获取mysql数据表的字段名称和详细信息的方法
2014/09/27 PHP
监控 url fragment变化的js代码
2010/04/19 Javascript
javascript制作sql转换为stringBuffer的小工具
2015/04/03 Javascript
使用AngularJS实现可伸缩的页面切换的方法
2015/06/19 Javascript
JavaScript实现删除,移动和复制文件的方法
2015/08/05 Javascript
高性能JavaScript 重排与重绘(2)
2015/08/11 Javascript
JS实现的鼠标跟随代码(卡通手型点击效果)
2015/10/26 Javascript
jQuery进行组件开发完整实例
2015/12/15 Javascript
基于Echarts 3.19 制作常用的图形(非静态)
2016/05/19 Javascript
微信小程序 教程之WXSS
2016/10/18 Javascript
jquery中done和then的区别(详解)
2017/12/19 jQuery
[01:56]林书豪DOTA2上海特级锦标赛励志短片
2016/03/05 DOTA
[07:54]DOTA2-DPC中国联赛 正赛 iG vs VG 选手采访
2021/03/11 DOTA
python快速查找算法应用实例
2014/09/26 Python
Python的for和break循环结构中使用else语句的技巧
2016/05/24 Python
Python使用matplotlib简单绘图示例
2018/02/01 Python
python实现批量解析邮件并下载附件
2018/06/19 Python
python调用百度语音REST API
2018/08/30 Python
selenium+python自动化测试之多窗口切换
2019/01/23 Python
Python3.6.x中内置函数总结及讲解
2019/02/22 Python
python制作填词游戏步骤详解
2019/05/05 Python
Python打开文件、文件读写操作、with方式、文件常用函数实例分析
2020/01/07 Python
pytorch nn.Conv2d()中的padding以及输出大小方式
2020/01/10 Python
python+django+selenium搭建简易自动化测试
2020/08/19 Python
Django model class Meta原理解析
2020/11/14 Python
python 检测图片是否有马赛克
2020/12/01 Python
AmazeUI图片轮播效果的示例代码
2020/08/20 HTML / CSS
英国女性时尚鞋类的潮流制造者:Koi Footwear
2018/10/19 全球购物
字符串str除首尾字符外的其他字符按升序排列
2013/03/08 面试题
便利店投资创业计划书
2014/02/08 职场文书
2015年导购员工作总结
2015/04/25 职场文书
给numpy.array增加维度的超简单方法
2021/06/02 Python
一文搞懂redux在react中的初步用法
2021/06/09 Javascript
关于Spring配置文件加载方式变化引发的异常详解
2022/01/18 Java/Android