你可以在django中使用模板表单的表单向导吗?

时间:2011-07-14 04:38:58

标签: python django django-models

我有一个模型,我使用ModelForm从模型中创建了一个表单。现在,我想将表单分散到两个页面。例如,前三个字段将显示在第一页上,然后用户单击下一个,最后三个字段显示在第二页上。然后他点击提交,用户提交的数据被添加到数据库中。

我看了一下表单向导的文档,看起来它也适用于模型表单?有人可以证实这一点吗?

如果确实如此,有人可以解释创建WizardView类的过程。

这个例子在文档中给出,我不明白后两个参数是什么。 form_list只是您根据表单类实例化的表单对象列表吗?什么是**kwargs

class ContactWizard(SessionWizardView):
    def done(self, form_list, **kwargs):
        do_something_with_the_form_data(form_list)
        return HttpResponseRedirect('/page-to-redirect-to-when-done/')

提前感谢您的帮助!

4 个答案:

答案 0 :(得分:22)

假设您的模型有两个字段

class AModel( Model ):
    fieldA = CharField()
    fieldB = CharField()

我们希望使用FormWizard在单独的步骤中设置每个字段。因此,我们创建两个ModelForm,每个显示一个字段:

class Form1( ModelForm ):
    class Meta:
        model = AModel
        fields = ( 'fieldA', )

class Form2( ModelForm ):
    class Meta:
        model = AModel
        fields = ( 'fieldB', )

我们调用表单向导AWizard; url.py条目应该类似于

url( r'^$', AWizard.as_view( [ Form1, Form2 ] ) ),

AWizard的实现中,我们需要确保所有表单将其数据写入单个实例,然后我们将其保存到数据库中:

class AWizard( SessionWizardView ):
    instance = None

    def get_form_instance( self, step ):
        if self.instance is None:
            self.instance = AModel()
        return self.instance

    def done( self, form_list, **kwargs ):
        self.instance.save()

请注意,我们覆盖方法get_form_instance。此方法返回表单绑定到的模型实例。

您可能认为(我这样做),此方法为第一个请求(向导的第一步)创建实例,然后继续对所有步骤使用相同的实例。

实际上,它有点复杂。对于每个请求,都会创建一个AWizard的新实例,从而创建一个新的AModel实例。因此,这些步骤不会共享单个实例。

提交最后一个表单时会发生魔力。此时,所有表单都会重新生效,每个表单调用get_form_instance,最终会填充单个AModel实例。

然后将该实例保存在done中。

答案 1 :(得分:6)

表单向导正在构建到Django 1.4中,因此这是一个很好的方法。它应该做你想要的,但你可能需要做一些调整。

暂时不要担心kwargs中的done() - 您根本不需要它们。

form_list是您要用于步骤的表单列表 - 来自urls.py

urlpatterns = patterns('',
    (r'^contact/$', ContactWizard.as_view([ContactForm1, ContactForm2])),
)

[ContactForm1, ContactForm2]done()传递给form_list

您需要做的是将ModelForm分成不同的形式。最简单的方法(如果你想要你的模型在几个表格上)是不使用ModelForm,而只是创建自己的表格。这很简单:

from django import forms

class ContactForm1(forms.Form):
    subject = forms.CharField(max_length=100)
    sender = forms.EmailField()

class ContactForm2(forms.Form):
    message = forms.CharField(widget=forms.Textarea)

一旦您的表单反映了模型的各个部分,只需按照docs中的说明创建viewspatterns,然后将do_something_with_the_form_data(form_list)设置为完成模型的函数从表单数据然后进行保存。

你可以使用ModelForm,但是 - 只有你可以说服它为表格向导制作不同的表格以用于每一步 - 这将是一个棘手的部分。

答案 2 :(得分:2)

@wuerg提出的观点对我不起作用,我不得不这样做:

class AWizard( SessionWizardView ):
    def dispatch(self, request, *args, **kwargs):
        self.instance = AModel()
        return super(ApplyWizard, self).dispatch(request, *args, **kwargs)

    def get_form_instance( self, step ):
        return self.instance

    def done( self, form_list, **kwargs ):
        self.instance.save()
        return HttpResponseRedirect(reverse(thanks))

答案 3 :(得分:0)

我必须改变@wuerg和@madmen的解决方案才能在我的用例中工作(在每一步之后保存模型)。这种方法的最大优点是它始终使用AModel的相同实例,而不是为每个步骤创建一个新实例:

class AWizard(SessionWizardView):
    instance = AModel()

    def dispatch(self, request, *args, **kwargs):
        return super(AWizard, self).dispatch(request, *args, **kwargs)

    def get_form_instance(self, step):
        return self.instance

    def done(self, form_list, **kwargs):
        self.save_model()
        return render_to_response('done.html')