资讯专栏INFORMATION COLUMN

Django中同一页面中的多表单处理

null1145 / 3361人阅读

摘要:原文地址关于在同个页面多个表单提交的问题实际上是项目中遇到的个小问题。实际关于在个页面提交多个表单的问题实际上问题不是很多只要解决了渲染和提交时处理的问题实际这个问题就迎刃而解了。

原文地址:

http://52sox.com/how-to-handl...

关于在同1个页面多个表单提交的问题,实际上是项目中遇到的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个表组成,分别为它的一些基础信息,可以配送的范围、天数及其他一些附加信息组成。然后其页面如下所示:

多表单渲染

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

在1个form组件中使用多个模型表单类

使用django提供的modelform_factory来解决

使用第3方插件django-betterforms或django-multipleformwizard这样的插件

使用元类,然后继承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))

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

{% csrf_token %} {{ sf.as_p }} {{ df.as_p }} {{ af.as_p }}

在这里,我们在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张表返回的结果,然后再进行保存。这样我们就实现了多张表的依赖导致的问题了。最后我们使用重定向的方式将成功添加后的页面跳转到该商户的仓库列表中。
其跳转后的页面如下所示:

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

参考文章:

http://stackoverflow.com/ques...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/38223.html

相关文章

  • Django搭建个人博客:文章标签功能

    摘要:每一篇文章的标签可能都不一样,并且还可能拥有多个标签,这是与栏目功能不同的。列表中显示标签虽然保存标签的功能已经实现了,还得把它显示出来才行。更多的用法请阅读官方文档总结本章学习了使用来完成标签功能。 标签是作者从文章中提取的核心词汇,其他用户可以通过标签快速了解文章的关注点。每一篇文章的标签可能都不一样,并且还可能拥有多个标签,这是与栏目功能不同的。 好在标签功能也有优秀的三方库:D...

    Amio 评论0 收藏0
  • Django 学习小组:博客开发实战第五周教程 —— 实现评论功能

    摘要:本教程内容已过时,更新版教程请访问博客开发入门教程。我们的评论表单放在中,评论成功后返回到原始提交页面。学习小组简介学习小组是一个促进新手互相学习互相帮助的组织。 本教程内容已过时,更新版教程请访问: django 博客开发入门教程。 通过前四周的时间我们开发了一个简单的个人 Blog,前几期教程地址: 第一周:Django 学习小组:博客开发实战第一周教程 —— 编写博客的 Mode...

    CoderStudy 评论0 收藏0
  • Django 学习小组:博客开发实战第五周教程 —— 实现评论功能

    摘要:本教程内容已过时,更新版教程请访问博客开发入门教程。我们的评论表单放在中,评论成功后返回到原始提交页面。学习小组简介学习小组是一个促进新手互相学习互相帮助的组织。 本教程内容已过时,更新版教程请访问: django 博客开发入门教程。 通过前四周的时间我们开发了一个简单的个人 Blog,前几期教程地址: 第一周:Django 学习小组:博客开发实战第一周教程 —— 编写博客的 Mode...

    kumfo 评论0 收藏0
  • Cesar竞赛平台项目期总结

    摘要:竞赛平台项目中期总结软件谢运帷我们小组的选题是大学生竞赛平台项目,经过我们需求分析,原型设计等等步骤,我们终于要开始着手实现这一个庞大的竞赛平台项目。 Cesar竞赛平台项目中期总结 软件51 谢运帷 2015013185 我们小组的选题是大学生竞赛平台项目,经过我们需求分析,原型设计等等步骤,我们终于要开始着手实现这一个庞大的竞赛平台项目。我们使用Django+mysql处理后端逻辑...

    rainyang 评论0 收藏0
  • Cesar竞赛平台项目期总结

    摘要:竞赛平台项目中期总结软件谢运帷我们小组的选题是大学生竞赛平台项目,经过我们需求分析,原型设计等等步骤,我们终于要开始着手实现这一个庞大的竞赛平台项目。 Cesar竞赛平台项目中期总结 软件51 谢运帷 2015013185 我们小组的选题是大学生竞赛平台项目,经过我们需求分析,原型设计等等步骤,我们终于要开始着手实现这一个庞大的竞赛平台项目。我们使用Django+mysql处理后端逻辑...

    mrcode 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<