gpt4 book ai didi

Django:重用表单字段而不继承?

转载 作者:行者123 更新时间:2023-12-04 15:03:56 24 4
gpt4 key购买 nike

如果我有两个基于不同基类(例如 Form 和 ModelForm)的表单,但我想在两者中使用一些字段,我可以以 DRY 方式重用它们吗?

考虑以下场景:

class AfricanSwallowForm(forms.ModelForm):
airspeed_velocity = forms.IntegerField(some_important_details_here)
is_migratory = forms.BooleanField(more_important_details)

class Meta:
model = AfricanBird

class EuropeanSwallowForm(forms.Form):
airspeed_velocity = forms.IntegerField(some_important_details_here)
is_migratory = forms.BooleanField(more_important_details)

....有没有一种方法可以重复使用 airspeed_velocity 和 is_migratory 字段?想象一下,我有几十种这样的表格。如果我一遍又一遍地写这些代码,代码会很累。

(假设,就这个问题而言,我不能或不会将 airspeed_velocity 和 is_migratory 转换为非洲鸟模型的字段。)

最佳答案

您可以使用多重继承(又名mixin)来分解在 Form 和 ModelForm 中使用的字段。

class SwallowFormFields:
airspeed_velocity = forms.IntegerField( ... )
is_migratory = forms.BooleanField( ... )

class AfricanSwallowForm(forms.ModelForm, SwallowFormFields):
class Meta:
model = AfricanBird

class EuropeanSwallowForm(forms.Form, SwallowFormFields):
pass

更新:

由于这不适用于 Django 元编程,您需要创建一个自定义 __init__将继承的字段添加到对象的字段列表的构造函数,或者您可以在类定义中显式添加引用:
class SwallowFormFields:
airspeed_velocity = forms.IntegerField()
is_migratory = forms.BooleanField()

class AfricanSwallowForm(forms.ModelForm):
airspeed_velocity = SwallowFormFields.airspeed_velocity
is_migratory = SwallowFormFields.is_migratory
class Meta:
model = AfricanSwallow

class EuropeanSwallowForm(forms.Form):
airspeed_velocity = SwallowFormFields.airspeed_velocity
is_migratory = SwallowFormFields.is_migratory

更新 :

当然,您不必将共享字段嵌套到类中——您也可以简单地将它们定义为全局变量......
airspeed_velocity = forms.IntegerField()
is_migratory = forms.BooleanField()

class AfricanSwallowForm(forms.ModelForm):
airspeed_velocity = airspeed_velocity
is_migratory = is_migratory
class Meta:
model = AfricanSwallow

class EuropeanSwallowForm(forms.Form):
airspeed_velocity = airspeed_velocity
is_migratory = is_migratory

更新:

好吧,如果你真的想最大限度地干燥,你必须使用 元类 .

所以你可以这样做:
from django.forms.models import ModelForm, ModelFormMetaclass
from django.forms.forms import get_declared_fields, DeclarativeFieldsMetaclass
from django.utils.copycompat import deepcopy

class MixinFormMetaclass(ModelFormMetaclass, DeclarativeFieldsMetaclass):
def __new__(cls, name, bases, attrs):

# default __init__ that calls all base classes
def init_all(self, *args, **kwargs):
for base in bases:
super(base, self).__init__(*args, **kwargs)
attrs.setdefault('__init__', init_all)

# collect declared fields
attrs['declared_fields'] = get_declared_fields(bases, attrs, False)

# create the class
new_cls = super(MixinFormMetaclass, cls).__new__(cls, name, bases, attrs)
return new_cls

class MixinForm(object):
__metaclass__ = MixinFormMetaclass
def __init__(self, *args, **kwargs):
self.fields = deepcopy(self.declared_fields)

您现在可以从 MixinForm 派生您的表单域集合,如下所示:
class SwallowFormFields(MixinForm):
airspeed_velocity = forms.IntegerField()
is_migratory = forms.BooleanField()

class MoreFormFields(MixinForm):
is_endangered = forms.BooleanField()

然后将它们添加到基类列表中,如下所示:
class EuropeanSwallowForm(forms.Form, SwallowFormFields, MoreFormFields):
pass

class AfricanSwallowForm(forms.ModelForm, SwallowFormFields):
class Meta:
model = AfricanSwallow

那么它有什么作用呢?
  • 元类收集在 MixinForm 中声明的所有字段
  • 然后添加自定义 __init__构造函数,以确保 __init__ MixinForm 的方法被神奇地调用。 (否则你将不得不显式调用它。)
  • MixinForm.__init__将声明的字段复制到字段属性

  • 请注意,我既不是 Python 大师也不是 django 开发人员,而且元类是危险的。因此,如果您遇到奇怪的行为,最好坚持使用上面更详细的方法:)

    祝你好运!

    关于Django:重用表单字段而不继承?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5184503/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com