代码之家  ›  专栏  ›  技术社区  ›  Krystian Cybulski

带有动态表单的Django表单向导

  •  6
  • Krystian Cybulski  · 技术社区  · 17 年前

    我想实现一个由两部分组成的简单表单向导。 表格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]
    

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

    我的第二张表格,实际上我不需要输入。我只想显示一个确认屏幕,其中包含信用卡信息、苹果信息和金额(总额、税款、运费)。一旦用户点击OK,我想开始购买苹果。

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

    __init__

    5 回复  |  直到 17 年前
        1
  •  4
  •   Tom Gruff    17 年前

    我没有用过,但是对于你描述的情况,你可能想试试这个 FormPreview 而不是表单向导。从文件上看,这听起来像是你想要的。

        2
  •  4
  •   Zak Patterson    14 年前

    当我试图找出FormWizard时,我搜索了所有地方,找到了像大多数这样的回答,它们只是说不要使用它。FormPreview可以正常工作,因为OP只对一级表单感兴趣,但在如何使用FormWizard中这个问题仍然有效。

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

    我认为就老年退休金问题而言,压倒一切的程序步骤才是前进的方向。诀窍在于在这个方法中创建表单(或视图),它将从第一个表单接收数据。

    我将此form_设置作为实用程序包装器添加到我的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
    

    然后按如下所示覆盖过程步骤:

    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])  #(*)
        ...
    

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

    编辑:请参阅Erik的评论,并澄清最后一部分。

    还请注意,将在步骤n之后的步骤[0,n]中调用进程u步骤。

        3
  •  0
  •   Krystian Cybulski    17 年前

    首先,放弃这个向导。

    两种观点: buy_apples 和 buy_apples_confirm

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

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

    1. 写出给出订单摘要的模板。此模板还将名为“确认”的隐藏字段设置为1(即使表单上不存在此字段)

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

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

        4
  •  0
  •   johan johan    17 年前

    谢谢你回答你自己的问题。帮助了我,但我还是得到了一些评论。

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

    Krys解决方案似乎和FormPreview做的一样。只有散列被省略,所以用户可以更改隐藏字段中的数据,或者您是否再次检查?。如果你再次检查它,那就不会是干的,因为你重复了检查(好的,可以是一个可重用的方法,所以只需要很小的重复)。

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

        5
  •  0
  •   hendrixski    16 年前

    换个房间怎么样 呼叫 方法获取额外的参数?

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

    推荐文章