在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中的__slots__示例详解
Jul 06 Python
利用标准库fractions模块让Python支持分数类型的方法详解
Aug 11 Python
浅谈flask截获所有访问及before/after_request修饰器
Jan 18 Python
python机器学习理论与实战(六)支持向量机
Jan 19 Python
Django 跨域请求处理的示例代码
May 02 Python
numpy中矩阵合并的实例
Jun 15 Python
对pandas中Series的map函数详解
Jul 25 Python
Python matplotlib生成图片背景透明的示例代码
Aug 30 Python
python如何获取apk的packagename和activity
Jan 10 Python
From CSV to SQLite3 by python 导入csv到sqlite实例
Feb 14 Python
django前端页面下拉选择框默认值设置方式
Aug 09 Python
Python使用pyenv实现多环境管理
Feb 05 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
PHP开发入门教程之面向对象
2006/12/05 PHP
用php+javascript实现二级级联菜单的制作
2008/05/06 PHP
深入理解PHP原理之异常机制
2010/08/21 PHP
PHP数组传递是值传递而非引用传递概念纠正
2013/01/31 PHP
解析用PHP读写音频文件信息的详解(支持WMA和MP3)
2013/05/10 PHP
PHP 使用header函数设置HTTP头的示例解析 表头
2013/06/17 PHP
PHP集成百度Ueditor 1.4.3
2014/11/23 PHP
php利用反射实现插件机制的方法
2015/03/14 PHP
CI框架数据库查询之join用法分析
2016/05/18 PHP
PHP实现微信提现功能(微信商城)
2019/11/21 PHP
Laravel 验证码认证学习记录小结
2019/12/20 PHP
ExtJs事件机制基本代码模型和流程解析
2010/10/24 Javascript
js 实现css风格选择器(压缩后2KB)
2012/01/12 Javascript
jquery实现按Enter键触发事件示例
2013/09/10 Javascript
Nodejs中读取中文文件编码问题、发送邮件和定时任务实例
2015/01/01 NodeJs
基于HTML模板和JSON数据的JavaScript交互(移动端)
2016/04/06 Javascript
jQuery 实现评论等级好评差评特效
2016/05/06 Javascript
基于Echarts 3.19 制作常用的图形(非静态)
2016/05/19 Javascript
jquery 动态增加,减少input表单的简单方法(必看)
2016/10/12 Javascript
ionic选择多张图片上传的示例代码
2017/10/10 Javascript
JS实现DOM删除节点操作示例
2018/04/04 Javascript
vue脚手架搭建项目的兼容性配置详解
2018/07/17 Javascript
js实现表格数据搜索
2020/08/09 Javascript
比较详细Python正则表达式操作指南(re使用)
2008/09/06 Python
Django objects.all()、objects.get()与objects.filter()之间的区别介绍
2017/06/12 Python
Python使用xlwt模块操作Excel的方法详解
2018/03/27 Python
python 缺失值处理的方法(Imputation)
2019/07/02 Python
Selenium常见异常解析及解决方案示范
2020/04/10 Python
canvas之万花筒效果的简单实现(推荐)
2016/08/16 HTML / CSS
Kathmandu英国网站:新西兰户外运动品牌
2017/03/27 全球购物
Booking.com美国:全球酒店预订网站
2017/04/18 全球购物
英国在线药房和在线医生:LloydsPharmacy
2019/10/21 全球购物
房屋出租委托书格式
2014/09/23 职场文书
租车协议书
2015/01/27 职场文书
教你用python控制安卓手机
2021/05/13 Python
用Python爬取各大高校并可视化帮弟弟选大学,弟弟直呼牛X
2021/06/11 Python