python 动态更新 ModelForm 的 Meta 类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/297383/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 19:51:10  来源:igfitidea点击:

Dynamically update ModelForm's Meta class

pythondjangodjango-formsmetaprogrammingmodelform

提问by ashchristopher

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 as_p(), as_ul(), etc does not reflect the updated Meta exclude.

我希望从我的角度动态更新 ModelForm 的内联 Meta 类。尽管此代码似乎更新从元类的排除列表,输出as_p()as_ul()等不反映更新的Meta排除。

I assume then that the html is generated when the ModelForm is created not when the as_*()is called. Is there a way to force the update of the HTML?

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

Is this even the best way to do it? I just assumed this shouldwork.

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

Thoughts?

想法?

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 = []

回答by Daniel Naab

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.

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

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

回答by user85461

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'])

回答by Hraban

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

类似的方法,有些不同的目标(任意模型的通用 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)

回答by keisuke

Use modelform_factory(doc):

使用modelform_factory文档):

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