cansadadeserfeliz
cansadadeserfeliz

Reputation: 3133

Extend Django ModelForm with a class

I have multiple model forms in my Django project and want to add three fields to all of them.

But when I write a simple form and then subclass it, I get an error.

class PersonForm(forms.Form):
    person_name = forms.CharField(
        label=u'Entregado por',
        max_length=64,
    )
    person_document_number = forms.CharField(
        label=u'Número de Documento',
        max_length=15,
    )
    person_document_type = forms.ChoiceField(
        label=u'Tipo de Documento',
        choices=BLANK_CHOICE_DASH + list(DOCUMENT_TYPE_CHOICES),
    )

class ContractForm(PersonForm, forms.ModelForm):
    class Meta:
        model = Contract

    def __init__(self, *args, **kwargs):
        super(ContractForm, self).__init__(*args, **kwargs)
        self.fields['person_name'].widget.attrs['class'] = 'js-person-name'

Error:

TypeError: Error when calling the metaclass bases
    metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

I tried to define a PersonForm like

class PersonForm:
    person_name = forms.CharField(
        label=u'Entregado por',
        max_length=64,
    )
    # ....

without inheriting it from forms.Form, and got an error:

django.core.exceptions.FieldError: Unknown field(s) (person_document_type, person_document_number, person_name) specified for Contract

Is there any beautiful way to do it (without copying these fields to all my model forms)?

Upvotes: 1

Views: 2047

Answers (1)

Du D.
Du D.

Reputation: 5310

Why not just implement PersonForm with ModelForm?

class PersonForm(forms.ModelForm):
    person_name = forms.CharField(
        label=u'Entregado por',
        max_length=64,
    )
    person_document_number = forms.CharField(
        label=u'Número de Documento',
        max_length=15,
    )
    person_document_type = forms.ChoiceField(
        label=u'Tipo de Documento',
        choices=BLANK_CHOICE_DASH + list(DOCUMENT_TYPE_CHOICES),
    )

class ContractForm(PersonForm):
    class Meta:
        model = Contract

    def __init__(self, *args, **kwargs):
        super(ContractForm, self).__init__(*args, **kwargs)
        self.fields['person_name'].widget.attrs['class'] = 'js-person-name'

Upvotes: 3

Related Questions