【问题标题】:Dynamically update ModelForm's Meta class动态更新 ModelForm 的 Meta 类
【发布时间】:2010-09-22 18:44:21
【问题描述】:

我希望从我的视图中动态更新 ModelForm 的内联 Meta 类。虽然这段代码似乎更新了 Meta 类中的排除列表,但 as_p()as_ul() 等的输出并未反映更新后的 Meta 排除。

我假设 html 是在创建 ModelForm 时生成的,而不是在调用 as_*() 时生成的。有没有办法强制更新 HTML?

这甚至是最好的方法吗?我只是假设这应该工作。

想法?

from django.forms import ModelForm

from testprogram.online_bookings.models import Passenger

class PassengerInfoForm(ModelForm):

    def set_form_excludes(self, exclude_list):
        self.Meta.exclude = excludes_list

    class Meta:
        model = Passenger
        exclude = []

【问题讨论】:

    标签: python django django-forms metaprogramming modelform


    【解决方案1】:

    Meta 类用于动态构造表单定义 - 因此,当您创建 ModelForm 实例时,不在 exclude 中的字段已添加为新对象的属性。

    通常的做法是为每个可能的排除列表设置多个类定义。但是,如果您希望表单本身是动态的,则必须动态创建类定义。比如:

    def get_form(exclude_list):
        class MyForm(ModelForm):
            class Meta:
                model = Passenger
                exclude = exclude_list
        return MyForm
    
    form_class = get_form(('field1', 'field2'))
    form = form_class()
    

    更新:我刚刚重温了这篇文章,并认为我会发布一些更惯用的方法来处理动态类:

    def PassengerForm(exclude_list, *args, **kwargs):
        class MyPassengerForm(ModelForm):
            class Meta:
                model = Passenger
                exclude = exclude_list
    
            def __init__(self):
                super(MyPassengerForm, self).__init__(*args, **kwargs)
    
        return MyPassengerForm()
    
    form = PassengerForm(('field1', 'field2'))
    

    【讨论】:

    • jule: 当然可以,只需在表单函数中添加一个位置参数:“def PassengerForm(exclude_list, model, *args, **kwargs)”,并以相同方式设置 Meta.model 字段Meta.exclude 已设置。
    • 如果您需要将实例传递给表单,则需要将 return MyPassengerForm() 替换为 return MyPassengerForm(*args, **kwargs)
    • @DanielNaab - 很有趣。我确实想知道我是否走错了路,但我必须添加*args, **kwargs 才能编辑现有实例;没有*args, **kwargsinstance=object 传递给表单不起作用(无论如何对我来说)
    • @DanielNaab 也许get_passenger_form 是比PassengerForm 更好的名称以符合其余代码的样式? PassengerForm 看起来像一个类,但它实际上是一个方法
    • @Erve1879 对我来说,它仅在实例通过的情况下返回 MyPassengerForm(*args, **kwargs) 时才有效。我认为原因是argskwargs被分配在上面MyPassengerForm的范围之外,所以当它实例化为MyPassengerForm()argskwargs时不包含任何内容。
    【解决方案2】:

    另一种方式:

    class PassengerInfoForm(ModelForm):
        def __init__(self, *args, **kwargs):
            exclude_list=kwargs.pop('exclude_list', '')
    
            super(PassengerInfoForm, self).__init__(*args, **kwargs)
    
            for field in exclude_list:
                del self.fields[field]
    
        class Meta:
            model = Passenger
    
    form = PassengerInfoForm(exclude_list=['field1', 'field2'])
    

    【讨论】:

    • 您可能应该使用 {}.pop() 而不是设置它然后删除它。 exclude_list = kwargs.pop('exclude_list') 保存一行代码。 耸耸肩
    • 正如@JustinAbrahms 所说,我希望您可以使用 kwargs.pop('exclude_list', default_value) 类似exclude_list=kwargs.pop('exclude_list', '')
    【解决方案3】:

    类似的方法,有些不同的目标(任意模型的通用 ModelForm):

    from django.contrib.admin.widgets import AdminDateWidget
    from django.forms import ModelForm
    from django.db import models
    
    def ModelFormFactory(some_model, *args, **kwargs):
        """
        Create a ModelForm for some_model
        """
        widdict = {}
        # set some widgets for special fields
        for field in some_model._meta.local_fields:
            if type(field) is models.DateField:
                widdict[field.name] = AdminDateWidget()
    
        class MyModelForm(ModelForm): # I use my personal BaseModelForm as parent
            class Meta:
                model = some_model
                widgets = widdict
    
        return MyModelForm(*args, **kwargs)
    

    【讨论】:

      【解决方案4】:

      使用modelform_factory (doc):

      from django.forms.models import modelform_factory
      
      from testprogram.online_bookings.models import Passenger
      
      exclude = ('field1', 'field2')
      CustomForm = modelform_factory(model=Passenger, exclude=exclude)  # generates ModelForm dynamically
      custom_form = CustomForm(data=request.POST, ...)  # form instance
      

      【讨论】:

        猜你喜欢
        • 2011-01-15
        • 2016-07-09
        • 1970-01-01
        • 2018-05-11
        • 1970-01-01
        • 2017-10-22
        • 1970-01-01
        • 2014-04-11
        • 1970-01-01
        相关资源
        最近更新 更多