Dynamically update ModelForm's Meta class

前端 未结 4 1064
执笔经年
执笔经年 2020-12-07 10:08

I am hoping to dynamically update a ModelForm\'s inline Meta class from my view. Although this code seems to update the exclude list in the Meta class, the output from

相关标签:
4条回答
  • 2020-12-07 10:28

    The Meta class is used to dynamically construct the form definition - so by the time you've created the ModelForm instance, the fields not in the exclude have already been added as the new object's attributes.

    The normal way to do it would be to just have multiple class definitions for each possible exclude list. But if you want the form itself to be dynamic, you'll have to create a class definition on the fly. Something like:

    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()
    

    UPDATE: I just revisited this post and thought I'd post a little more idiomatic way to handle a dynamic 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'))
    
    0 讨论(0)
  • 2020-12-07 10:30

    Use 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
    
    0 讨论(0)
  • 2020-12-07 10:39

    Another way:

    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'])
    
    0 讨论(0)
  • 2020-12-07 10:44

    Similar approach, somewhat different goal (generic ModelForm for arbitrary models):

    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)
    
    0 讨论(0)
提交回复
热议问题