2013-03-13 62 views
4

我的Django应用程序使用Django Suit作为主题管理Django应用程序的工具。的事情之一西装能做的就是追加和预先准备的元素,形成像小部件:在Django中动态修改表单部件

class PropertyForm(ModelForm): 
    class Meta: 
     model = Property 
     widgets = { 
      'amount': EnclosedInput(prepend = "GBP"), 
     } 

的效果是:

enter image description here

虽然这是一个很好的功能,如果我会比较有用可以增加它动态等(伪代码):

'amount': EnclosedInput(prepend = my_model_instance.currency) 

我试图重写形式的init像这样:

class PropertyForm(ModelForm): 

    def __init__(self, *args, **kwargs): 
     inst = kwargs["instance"] 
     self._meta.widgets["amount"] = EnclosedInput(prepend = inst.currency) 
     super(PropertyForm, self).__init__(*args, **kwargs) 

奇怪的是,当我把一个断点在初始化方法仅适用。看起来有一些时间问题。

所以我的问题是什么将是最好的方式(如果一个可用)来实现这个?

+0

你需要的是从多个取其值小部件实例字段。一种方法是使用'MultiValueField'和'MultiWidget'。如果这太难以工作,我可以阐述一个答案。 – 2013-03-13 11:29:23

+0

我不太确定这是要走的路。当我查看EnclosedInput(Django Suit的一部分)的代码时,这个小部件只是标准Django TextInput的扩展,他们所做的唯一事情就是将一个带有CSS类的添加到该小部件的HTML输出中。我真的很困惑的事实,我的方法不工作没有断点和调试器停止... – Roger 2013-03-13 12:22:15

+0

我的意思是,你基本上想要一个包含两个不同表单域的值的小部件。我认为这是一种比黑客入侵窗体构造器更可重用的解决方案。至于调试器,也许它强制评估一些懒惰的对象? – 2013-03-13 12:29:06

回答

8

的问题是:

self._meta.widgets["amount"] = EnclosedInput(prepend = inst.currency) 

原来_meta被缓存。当我改变上述行(这也一个更好的解决方案,_meta可能是私人):

self.fields['amount'].widget = EnclosedInput(prepend = inst.currency) 

...它完美的作品

1

一个简单的办法是每次配置表单类,你需要它:

def make_property_form(currency): 
    class PropertyForm(forms.Form): 
     # ... 
     widgets = { 
      'amount': EnclosedInput(prepend=currency), 
     } 
    return PropertyForm 

def view_that_uses_my_form(request): 
    # ... 
    form_class = make_property_form(model.currency) 
    form = form_class(the_usual_form_initialization) 
+0

表单在管理中配置form = PropertyForm,所以这将意味着我需要将这些方法添加到PropertyAdmin类?我还需要重写实际创建窗体的admin方法(可能是您的答案中的view_that_uses_my_form()方法... – Roger 2013-03-13 11:21:16

+0

不,这会使我的方法在您的案例中变得毫无用处,它只会在您明确构建新的表单实例在每次使用(如果你只在你自己的视图函数中使用表单),但我不会惹恼这个管理代码。 – 2013-03-13 11:24:22