在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 相关文章推荐
详解Python3中字符串中的数字提取方法
Jan 14 Python
Python3 读、写Excel文件的操作方法
Oct 20 Python
python中的协程深入理解
Jun 10 Python
python实现两个经纬度点之间的距离和方位角的方法
Jul 05 Python
Django 创建/删除用户的示例代码
Jul 24 Python
python实现简单图书管理系统
Nov 22 Python
Python图片的横坐标汉字实例
Dec 04 Python
python打印异常信息的两种实现方式
Dec 24 Python
Pytorch之contiguous的用法
Dec 31 Python
Python如何输出警告信息
Jul 30 Python
Pycharm如何自动生成头文件注释
Nov 14 Python
PyTorch 如何自动计算梯度
May 23 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
自己动手,丰衣足食 - 短波框形天线制作
2021/03/01 无线电
多重?l件?合查?(一)
2006/10/09 PHP
PHP简单系统数据添加以及数据删除模块源文件下载
2008/06/07 PHP
phplot生成图片类用法详解
2015/01/06 PHP
基于PHP实现栈数据结构和括号匹配算法示例
2017/08/10 PHP
thinkphp ajaxfileupload实现异步上传图片的示例
2017/08/28 PHP
js获取url参数的使用扩展实例
2007/12/29 Javascript
Node.js和PHP根据ip获取地理位置的方法
2014/03/14 Javascript
jQuery中:only-child选择器用法实例
2015/01/03 Javascript
使用CDN和AJAX加速WordPress中jQuery的加载
2015/12/05 Javascript
jQuery添加和删除输入文本框标签代码
2016/05/20 Javascript
基于JQuery实现分隔条的功能
2016/06/17 Javascript
Vue概念及常见命令介绍(1)
2016/12/08 Javascript
原生js实现对Ajax的封装(仿jquery)
2017/01/22 Javascript
通过npm引用的vue组件使用详解
2017/03/02 Javascript
ES6解构赋值的功能与用途实例分析
2017/10/31 Javascript
微信小程序loading组件显示载入动画用法示例【附源码下载】
2017/12/09 Javascript
AngularJS上传文件的示例代码
2018/11/10 Javascript
vue插件--仿微信小程序showModel实现模态提示窗功能
2020/08/19 Javascript
Vue实现简单的留言板
2020/10/23 Javascript
python中Pycharm 输出中文或打印中文乱码现象的解决办法
2017/06/16 Python
浅谈numpy库的常用基本操作方法
2018/01/09 Python
Python装饰器模式定义与用法分析
2018/08/06 Python
Python实现的栈、队列、文件目录遍历操作示例
2019/05/06 Python
Python3和pyqt5实现控件数据动态显示方式
2019/12/13 Python
Html5实现单张、多张图片上传功能
2019/04/28 HTML / CSS
基于HTML5+CSS3实现简单的时钟效果
2017/09/11 HTML / CSS
VIVOBAREFOOT赤脚鞋:让您的脚做自然的事情
2017/06/01 全球购物
西班牙多品牌鞋店连锁店:Krack
2018/11/30 全球购物
篮球比赛策划方案
2014/06/05 职场文书
担保贷款承诺书
2015/04/30 职场文书
2015年卫生监督工作总结
2015/05/21 职场文书
成功的商业计划书这样写才最靠谱
2019/07/12 职场文书
导游词之寿县报恩寺
2020/01/19 职场文书
zabbix监控mysql的实例方法
2021/06/02 MySQL
MySQL 亿级数据导入导出及迁移笔记
2021/06/18 MySQL