usted podría utilizar la herencia múltiple aka mixins, a factorizar los campos que se usan en Form y 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
ACTUALIZACIÓN:
Dado que este no funciona con Django metaprogramming, que sea necesario crear un __init__
constructor personalizado que agrega los campos heredados a la lista de campos del objeto o puede agregar las referencias explícitamente dentro de la definición de clase:
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
ACTUALIZACIÓN:
Por supuesto que no tiene que anidan sus campos compartidos en una clase - que también podría simplemente definirlas como globales ...
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
ACTUALIZACIÓN:
bien, si Realmente quiero SECAR al máximo, tienes que ir con las metaclases.
Así que aquí es cómo puede hacerlo:
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)
Ahora se puede derivar sus colecciones de FormFields de MixinForm así:
class SwallowFormFields(MixinForm):
airspeed_velocity = forms.IntegerField()
is_migratory = forms.BooleanField()
class MoreFormFields(MixinForm):
is_endangered = forms.BooleanField()
A continuación, añadirlos a la lista de clases base como esto:
class EuropeanSwallowForm(forms.Form, SwallowFormFields, MoreFormFields):
pass
class AfricanSwallowForm(forms.ModelForm, SwallowFormFields):
class Meta:
model = AfricanSwallow
¿Qué hace?
- La metaclase recoge todos los campos declarados en su MixinForm
- A continuación, agrega personalizados
__init__
constructores, para asegurarse de que el método de la MixinForm __init__
se llama mágicamente. (De lo contrario, tendría que llamarlo de manera explícita.)
MixinForm.__init__
copia los campos declarados int el campo de atributo
Tenga en cuenta que no soy ni un gurú, ni un desarrollador de Python Django, y que metaclases son peligrosos. Entonces, si te encuentras con un comportamiento extraño mejor quédate con el enfoque más detallado anterior :)
¡Buena suerte!
Al principio, miré esto y lo descarté, pensando que era maravilloso pero demasiado difícil de manejar para el uso en el mundo real. Después de una segunda lectura, me doy cuenta de que este es un enfoque increíble. Funciona perfectamente, y es lo suficientemente legible con algunos comentarios adicionales. – jMyles