首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Django:重用表单字段而不继承?

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

Stack Overflow用户
提问于 2011-03-04 01:52:26
回答 4查看 1.6K关注 0票数 6

如果我有两个表单,基于不同的基类(比如Form和ModelForm),但是我想在这两个表单中都使用几个字段,我能以一种干的方式重用它们吗?

考虑以下场景:

代码语言:javascript
复制
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的字段。)

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-03-04 03:37:15

一种工厂式的方法怎么样?

代码语言:javascript
复制
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),
    })

因此,您可以在此处修改工厂函数,以查看现有的表单类并挑选出所需的属性,这样就不会丢失声明性语法……

票数 1
EN

Stack Overflow用户

发布于 2011-03-04 02:24:30

您可以使用多个继承(也称为mixins )来提取在Form和ModelForm中都使用的字段。

代码语言:javascript
复制
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__构造函数来将继承的字段添加到对象的字段列表中,或者您可以在类定义中显式添加引用:

代码语言:javascript
复制
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

更新

当然,您不必将共享字段嵌套到一个类中--您也可以简单地将它们定义为全局变量……

代码语言:javascript
复制
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.

所以你可以这样做:

代码语言:javascript
复制
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派生表单字段集合,如下所示:

代码语言:javascript
复制
class SwallowFormFields(MixinForm):
    airspeed_velocity = forms.IntegerField()
    is_migratory = forms.BooleanField()

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

然后将它们添加到基类列表中,如下所示:

代码语言:javascript
复制
class EuropeanSwallowForm(forms.Form, SwallowFormFields, MoreFormFields):
    pass

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

那么它能做什么呢?

  • 元类收集您的MixinForm
  • 中声明的所有字段,然后添加自定义__init__构造函数,以确保MixinForm的__init__方法被神奇地调用。(否则,您将不得不将声明的字段复制到字段属性

请注意,我既不是Python专家,也不是django开发人员,元类是危险的。因此,如果您遇到奇怪的行为,最好使用上面更冗长的方法:)

祝好运!

票数 6
EN

Stack Overflow用户

发布于 2012-07-06 09:53:38

创建IntegerField的子类

代码语言:javascript
复制
class AirspeedField(forms.IntegerField):
    def __init__():
        super(AirspeedField, self).__init__(some_important_details_here)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5184503

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档