在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 SQLAlchemy基本操作和常用技巧(包含大量实例,非常好)
May 06 Python
在Mac下使用python实现简单的目录树展示方法
Nov 01 Python
Python字典循环添加一键多值的用法实例
Jan 20 Python
使用python实现简单五子棋游戏
Jun 18 Python
django 邮件发送模块smtp使用详解
Jul 22 Python
python 函数的缺省参数使用注意事项分析
Sep 17 Python
Python三元运算与lambda表达式实例解析
Nov 30 Python
Python list运算操作代码实例解析
Jan 20 Python
python实现人机猜拳小游戏
Feb 03 Python
Python中猜拳游戏与猜筛子游戏的实现方法
Sep 04 Python
matplotlib绘制鼠标的十字光标的实现(自定义方式,官方实例)
Jan 10 Python
Python 循环读取数据内存不足的解决方案
May 25 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
十大催泪虐心动漫电影,有几部你还没看
2020/03/04 日漫
PHP微信开发之查询城市天气
2016/06/23 PHP
thinkphp在php7环境下提示Cannot use ‘String’ as class name as it is reserved的解决方法
2016/09/30 PHP
php 实现一个字符串加密解密的函数实例代码
2016/11/01 PHP
PHP实现图片压缩
2020/09/09 PHP
Yii框架日志操作图文与实例详解
2019/09/09 PHP
JS随机调用指定函数的方法
2015/07/01 Javascript
js计算系统当前日期是星期几的方法
2016/07/14 Javascript
javascript 动态脚本添加的简单方法
2016/10/11 Javascript
js+div+css下拉导航菜单完整代码分享
2016/12/28 Javascript
vue实现全选和反选功能
2017/08/31 Javascript
jQuery Ajax向服务端传递数组参数值的实例代码
2017/09/03 jQuery
让Vue也可以使用Redux的方法
2018/05/23 Javascript
VUEX 数据持久化,刷新后重新获取的例子
2019/11/12 Javascript
js实现tab栏切换效果
2020/08/02 Javascript
JSON stringify方法原理及实例解析
2020/10/23 Javascript
[03:21]辉夜杯主赛事 12月25日TOP5
2015/12/26 DOTA
使用Python编写提取日志中的中文的脚本的方法
2015/04/30 Python
Python对列表排序的方法实例分析
2015/05/16 Python
Python的Tornado框架实现图片上传及图片大小修改功能
2016/06/30 Python
Python实现快速计算词频功能示例
2018/06/25 Python
Numpy中的mask的使用
2018/07/21 Python
python截取两个单词之间的内容方法
2018/12/25 Python
使用css实现android系统的loading加载动画
2019/07/25 HTML / CSS
澳大利亚网上书店:QBD
2021/01/09 全球购物
客服部班长工作责任制
2014/02/25 职场文书
学生自我评语大全
2014/04/18 职场文书
爱与责任师德演讲稿
2014/08/26 职场文书
党员自评材料范文
2014/12/17 职场文书
3.15消费者权益日活动总结
2015/02/09 职场文书
幼儿园园务工作总结2015
2015/05/18 职场文书
2016教师六五普法学习心得体会
2016/01/21 职场文书
二年级数学教学反思
2016/02/16 职场文书
SqlServer: 如何更改表的文件组?(进而改变存储位置)
2021/04/05 SQL Server
golang slice元素去重操作
2021/04/30 Golang
千万级用户系统SQL调优实战分享
2022/03/03 MySQL