【问题标题】:Change a django form class before it is instantiated在实例化之前更改 django 表单类
【发布时间】:2013-11-11 20:26:45
【问题描述】:

我想知道是否可以在实例化之前更改或更改表单类。

作为一个具体的例子,我有一个支付表单,需要根据所使用的支付系统进行修改。

理想情况下,我宁愿不创建不同的表单类,然后根据支付系统选择不同的表单类;相反,支付系统对象将“告诉”表单类它需要进行哪些更改——例如,使某些字段可选或指示它们使用不同的小部件。

这可能吗?另一种方法是将代表支付系统的对象传递到表单中,然后让它在实例化后修改表单,但是让它在表单类而不是视图中运行似乎有点笨拙。我觉得 Django 的“视图”更接近于控制器,而且似乎这就是应该发生这种事情的地方。我也觉得修改它会更好地修改 form_class 对象而不是表单实例;我什至不确定当您在这样的事实之后添加字段时,它是否会正确处理验证和表单填写。会吗?

在任何地方,这里有一些示例代码,说明如何将支付对象传递给表单实例化调用:

payment_system.py:

class ExamplePaymentSystem(BasePaymentSystem):
    def modify_form(self, form):
        for fld in self.optional_fields:
            form.fields[fld].required = False
        …etc…

forms.py:

class ModifiablePaymentForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        self.payment_system = kwargs.pop("payment_system", None)
        super(ModifiablePaymentSystem, self).__init__(*args, **kwargs)
        self.payment_system.modify_form(self)

【问题讨论】:

  • 那么,您宁愿让payment_system 修改表单,还是为每个支付系统创建多个表单类?问题的描述似乎与标题相矛盾。
  • 不管你如何描述它,我更喜欢表单类,而不是表单实例。我给出的示例使用了表单实例,因为我不确定修改表单类的好方法。我希望更改表单类以匹配支付系统的需求。对于给定的购买请求,只有一个支付系统在使用,所以我不需要它来一次创建一堆表单类;我只需要它为该支付系统创建正确的表单。完美的例子是Stripe,其中支付字段应该有名称。

标签: python django django-forms


【解决方案1】:

您不应该修改全局静态数据(在模块范围内定义的类是静态的),因为如果您在每个进程的多个线程中运行代码(通常这样做),一个线程可能会修改其他线程使用的表单类。

如果您的支付系统是静态的(您不会在服务器运行时即时添加新系统),我会为每个支付系统定义一个表单。

如果没有,您可以随时像这样动态定义新的表单类型:

 def get_form_type(payment_system): 
    class DynamicForm(BasePaymentForm): 
        ... add change fields etc... 
    return DynamicForm

或像这样修改实例:

class PaymentForm(BasePaymentForm): 

     def __init__(self, ..., payment_system):
         self.fields['foo'].required = False # <--- I'm writing code 
         #from the memory, so possibly you'll need t edit it 
         #but this is doable and easy to do. 

如何删除表单中的字段(根据 OP 请求)。

子类化时:

这很难,我认为您需要浏览表单内部并在创建子类后手动修改它们。 这是一个疯狂的猜测......

 def get_form_type(payment_system): 
    class DynamicForm(BasePaymentForm): 
        ... add change fields etc... 
    del DynamicForm.base_fields['foo']
    return DynamicForm

修改实例时: 我不是 100% 确定,但我偷看了 django 源代码(不幸的是,这些细节不在文档中)。但我想你应该:

 class PaymentForm(BasePaymentForm): 
     def __init__(self, ..., payment_system):
         del self.fields['foo']

fieldsdict(或者我猜——OrderedDict),要删除字段,您需要删除整个键值映射。

【讨论】:

  • 这似乎有道理。在__init__ 期间修改会修改实例,而不是类,对吗?
  • 这取决于您修改的内容(您仍然可以访问某处的类)错误 django 显式复制类中定义的字段,并将这些副本附加到实例,因此您应该是安全的。
  • 如果不想显示我要子类化的表单中的字段,我是否应该在子类中将其设置为None,即class BaseFoo(object):(break)foo=form.CharField...)然后class DynamicFoo(BaseFoo):(break)foo=None?跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-02
相关资源
最近更新 更多