如果我有两个表单,基于不同的基类(比如Form和ModelForm),但是我想在这两个表单中都使用几个字段,我能以一种干的方式重用它们吗?
考虑以下场景:
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转换为模型AfricanBird的字段。)
发布于 2011-03-04 03:37:15
一种工厂式的方法怎么样?
def form_factory(class_name, base, field_dict):
always_has = {
'airspeed_velocity': forms.IntegerField(some_important_details_here),
'is_migratory': forms.BooleanField(more_important_details)
}
always_has.update(field_dict)
return type(class_name, (base,), always_has)
def meta_factory(form_model):
class Meta:
model = form_model
return Meta
AfricanSwallowForm = form_factory('AfricanSwallowForm', forms.ModelForm, {
'other' = forms.IntegerField(some_important_details_here),
'Meta': meta_factory(AfricanBird),
})
EuropeanSwallowForm = form_factory('EuropeanSwallowForm', forms.Form, {
'and_a_different' = forms.IntegerField(some_important_details_here),
})因此,您可以在此处修改工厂函数,以查看现有的表单类并挑选出所需的属性,这样就不会丢失声明性语法……
发布于 2011-03-04 02:24:30
您可以使用多个继承(也称为mixins )来提取在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更新:
好的,如果你真的想干到最大,你就得用metaclasses.
所以你可以这样做:
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那么它能做什么呢?
__init__构造函数,以确保MixinForm的__init__方法被神奇地调用。(否则,您将不得不将声明的字段复制到字段属性中
请注意,我既不是Python专家,也不是django开发人员,元类是危险的。因此,如果您遇到奇怪的行为,最好使用上面更冗长的方法:)
祝好运!
发布于 2012-07-06 09:53:38
创建IntegerField的子类
class AirspeedField(forms.IntegerField):
def __init__():
super(AirspeedField, self).__init__(some_important_details_here)https://stackoverflow.com/questions/5184503
复制相似问题