6

我想实现一个简单的 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 不是正确的方法吗?如果是,Form__init__方法如何从 HTTP 请求中访问用户对象?

4

5 回答 5

4

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

于 2008-12-11T12:14:22.403 回答
4

当我试图弄清楚 FormWizard 时,我搜索了所有内容,并找到了诸如大多数这些只是说不要使用它的响应。FormPreview 可以正常工作,因为 OP 只对一级表单感兴趣,但问题在如何使用 FormWizard 方面仍然有效。

尽管这个问题太老了,但我认为在这里回答很有价值,因为这个问题在很多网站上都被问到了,我没有看到对它的一致回应,也没有在文档中给出明确的解决方案。

我认为就 OPs 问题而言,覆盖 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。

于 2011-02-01T01:39:11.620 回答
0

我不知道回答自己的问题是否是 StackOverflow 上可接受的行为,这是我对自己问题的解决方案。

首先,抛弃 FormWizard。

我有一个表格。两种观点:buy_applesbuy_apples_confirm

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

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

  1. 将所有字段上的小部件调整为 HiddenInput
  2. 写出提供订单摘要的模板。此模板还将一个名为“确认”的隐藏字段设置为 1(即使表单上不存在此字段)

当用户点击购买苹果时,表单被提交回来并再次buy_apples_confirm调用视图。这一次,出现了一个名为“confirm”的 POST 参数,因此我们实际处理了购买交易并且用户得到了他的苹果。

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

于 2008-12-11T06:18:07.600 回答
0

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

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

Krys 解决方案似乎与 FormPreview 一样。只有散列被遗漏了,所以用户可以更改隐藏字段中的数据,或者您是否再次检查它?如果您再次检查它,那将不会遵循 DRY,因为您重复了检查(好吧,可能是可重用的方法,所以只有很小的重复)。

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

于 2009-03-12T10:43:10.763 回答
0

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

类似的东西:http: //dw.me/blog/2010/3/18/15/

于 2010-05-03T02:38:48.577 回答