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

原文地址:

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个表组成,分别为它的一些基础信息,可以配送的范围、天数及其他一些附加信息组成。然后其页面如下所示:

1.jpg

多表单渲染

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

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

  • 使用django提供的modelform_factory来解决

  • 使用第3方插件django-betterformsdjango-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))

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

<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个表单中输出多个表单,其页面如下所示:

2.jpg

可以看到其效果与后台的页面相差不是很大,只是没有对应的样式而已。

多表单提交外键处理

接着我们需要处理多个表单提交时的处理问题。

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

3.jpg

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

参考文章:

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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Django forms是一个用于处理表单的高级工具集,它提供了许多便捷的方法和函数,可以轻松地创建和处理表单Django forms的要作用是将HTML表单Python代码联系起来,使得表单的输入数据可以被方便地处理和验证。 使用Django forms处理表单的基本步骤如下: 1. 创建一个表单类,该类继承自Django forms的forms.Form类。 2. 在表单定义需要处理表单字段,可以使用Django forms提供的各种字段类型,如CharField、IntegerField等。 3. 在表单定义处理表单数据的方法,一般是通过Django forms的cleaned_data属性获取表单数据,并进行相应的处理和验证。 4. 在视图函数实例化表单类,并将接收到的请求数据传递给表单类实例,然后调用表单定义的处理表单数据的方法进行处理。 5. 如果表单数据验证通过,可以执行相应的逻辑,如果验证失败,可以重新渲染表单并输出错误提示信息。 以下是一个简单的Django forms表单处理示例代码: ```python # forms.py from django import forms class ContactForm(forms.Form): name = forms.CharField(max_length=100) email = forms.EmailField() message = forms.CharField(widget=forms.Textarea) def send_email(self): # 处理表单数据的方法 name = self.cleaned_data['name'] email = self.cleaned_data['email'] message = self.cleaned_data['message'] # 进行邮件发送等操作 ``` ```python # views.py from django.shortcuts import render from .forms import ContactForm def contact_view(request): if request.method == 'POST': form = ContactForm(request.POST) if form.is_valid(): form.send_email() return render(request, 'success.html') else: form = ContactForm() return render(request, 'contact.html', {'form': form}) ``` 在上面的示例代码,我们定义了一个名为ContactForm的表单类,该类继承自Django forms的forms.Form类,然后定义了三个需要处理表单字段:name、email和message。在表单还定义了一个名为send_email的处理表单数据的方法,该方法通过cleaned_data属性获取表单数据,并进行相应的处理和验证。 在视图函数contact_view,我们首先判断请求方法是否为POST,如果是POST请求,则实例化ContactForm表单类并将请求数据传递给它,然后调用is_valid方法进行表单数据验证。如果表单验证通过,我们就可以调用表单定义的send_email方法进行处理。如果表单验证失败,我们可以重新渲染表单并输出错误提示信息。 以上就是使用Django forms处理表单的基本步骤,通过Django forms,我们可以轻松地处理表单数据,并进行相应的验证和处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值