Django FormWizard与动态形式

时间:2008-12-11 04:13:41

标签: django forms dynamic formwizard

我想实现一个简单的2部分FormWizard。 表单1将动态生成如下内容:

class BuyAppleForm(forms.Form):
   creditcard = forms.ChoiceField(widget = forms.RadioSelect)
   type = forms.ChoiceField(widget = forms.RadioSelect)
   def __init__(self,*args, **kwargs):
        user = kwargs['user']
        del kwargs['user']

        super(BuyAppleForm, self).__init__(*args, **kwargs)

        credit_cards = get_credit_cards(user)
        self.fields['creditcard'].choices = [(card.id,str(card)) for card in credit_cards]

        apple_types= get_types_packages()
        self.fields['type'].choices = [(type.id,str(type)) for type in apple_types]

这将动态创建一个包含可用选项列表的表单。

我的第二种形式,我实际上不想输入。我只想显示一个确认屏幕,其中包含信用卡信息,苹果信息和金额(总金额,税金,运费)。用户单击“确定”后,我希望开始购买苹果。

我能够通过传入kwargs中的request.user对象来实现单一表单方式。但是,使用FormWizard,我无法理解这一点。

我是否接近问题并且FormWizard不是正确的方法吗?如果是,表单__init__方法如何从HTTP请求访问用户对象?

5 个答案:

答案 0 :(得分:4)

我没有使用它,但对于你描述的情况,似乎你可能想尝试FormPreview而不是FormWizard。从文档中,它听起来像你正在追求的。

答案 1 :(得分:4)

当我试图弄清楚FormWizard的时候,我搜遍了所有的回答,发现大多数这些只是说不要使用它的回复。 FormPreview可以正常工作,因为OP只对单级表单感兴趣,但问题仍然是如何使用FormWizard。

尽管这个问题已经过时了,但我认为回答这个问题很有价值,因为这个问题在很多网站上被提出,我看不到对它的回应,也没有明确的解决方案。

我认为就OP问题而言,重写process_step是可行的方法。诀窍是在此方法中创建将从第一种形式接收数据的表单(或视图)。

我将这个form_setup作为实用程序包装器(想象构造函数)添加到我的forms.py中:

def form_setup(**kwargs):
    def makeform(data, prefix=None, initial=None):
        form = FormLev2(data, prefix, initial)
        for k, v in kwargs.items():
            if k == 'some_list':
                form.fields['some_list'].choices = v
            ...
        return form
    return makeform

然后按如下方式覆盖process_step:

def process_step(self, request, process, step):
    if step == 1
        if form.is_valid():  #form from step 1
            objs = Table.objects.filter(...) #based on last form 
            self.form_list[1] = form_setup(some_list=[(o.id,o.name) for o in objs])  #(*)
    ...

这样,您可以动态修改form_list(*),即修改FormWizard实例中的form_list,而不是表单定义本身。包装函数对于此功能至关重要,因为它返回一个函数,该函数将实例化一个新的Form对象,然后在FormWizard中使用该函数调用下一个表单的数据,并允许您使用前一个表单中的数据。

编辑:对于Erik的评论,并澄清最后一部分。

另请注意,在步骤n之后将使用步骤[0,n]调用process_step。

答案 2 :(得分:0)

我不知道在StackOverflow上回答一个人自己的问题是否是可接受的行为,这是我解决自己问题的方法。

首先,沟渠FormWizard。

我有一张表格。 两种观看次数:buy_applesbuy_apples_confirm

第一个视图只处理GET。它打印出未绑定的表单,并带有转到第二个视图的URL的操作。

第二个视图检查是否存在名为“confirm”的POST参数。如果它不存在(因为它不是第一次加载视图时):

  1. 将所有字段上的小部件调整为HiddenInput
  2. 写出提供订单摘要的模板。此模板还将名为“confirm”的隐藏字段设置为1(即使表单上不存在此字段)
  3. 当用户点击购买苹果时,表单将被提交回来,并再次调用buy_apples_confirm视图。这次,出现了一个名为“confirm”的POST参数,因此我们实际上处理了购买交易并且用户得到了他的苹果。

    我欢迎对这种方法的任何批评或处理这种情况的更好方法。我是Django的新手,发现有很多不同的方法可以解决问题。我想从最好的方面学习。

答案 3 :(得分:0)

谢谢krys回答你自己的问题。帮助了我,但我仍有一些评论。

FormPreview不是要走的路,因为据我所知,它不支持动态表单。它依赖于固定的表单类来从那里生成from。但我们在这里用函数动态生成。也许FormPreview将支持这一天(或已经确实,我不知道如何)。

Krys解决方案似乎与FormPreview一样。只剩下哈希值,因此用户可以更改隐藏字段中的数据,还是再次检查?如果你再次检查它,那将不会跟随干,因为你复制了支票(好吧,可能是一个可重复使用的方法,所以只有很小的重复)。

我想知道,你如何调整小部件?您是否使用新窗口小部件复制表单,或者有没有办法动态更改它?

答案 4 :(得分:0)

如何更改调用方法以获取额外参数?

类似于此:http://d-w.me/blog/2010/3/18/15/