Buddyshot
Buddyshot

Reputation: 1684

Conditional fields in a ModelForm.Meta

Assume we have a custom user model in a Django application. In order to make it CRUDable from the admin page, we want to define some forms.

Below is the UserChangeForm used to modify an instance of our custom user model

class UserChangeForm(forms.ModelForm):

    class Meta:
        model  = MyCustomUser
        fields = (
            ...,
            'email',
            'is_active',
            'is_admin',
            'groups',
            ....
        )

The question is: how do I implement a conditional fields in the Meta class based on the model instance (i.e., out of scope for Meta)?

The goal is to declare something like

def get_fields(self):
    if self.instance.is_company:
        return ('email', 'company_name', 'headquarters')
    else:
       return ('email', 'first_name', 'last_name')

in the outer class, then find a way to inject the result of the function in Meta.fields. Any idea?

Upvotes: 1

Views: 1105

Answers (2)

Alasdair
Alasdair

Reputation: 308899

If you're using the Django admin, you can use the ModelAdmin.get_fields method.

class UserModelAdmin(admin.ModelAdmin):
    ...
    def get_fields(request, obj=None):
        if obj is None:
            return ('email', ...) # suitable list of fields for adding object
        elif obj.is_company:
            return ('email', 'company_name', 'headquarters')
        else:
            return ('email', 'first_name', 'last_name')

Upvotes: 2

catavaran
catavaran

Reputation: 45575

You can delete fields from the form in the __init__() constructor:

class UserChangeForm(forms.ModelForm):

    class Meta:
        fields = ('email', 'company_name', 'headquarters',
                           'first_name', 'last_name', )

    def __init__(self, *args, **kwargs):
        super(UserChangeForm, self).__init__(*args, **kwargs)
        if self.instance.is_company:
            fields_to_delete = ('first_name', 'last_name')
        else:
            fields_to_delete = ('company_name', 'headquarters')
        for field in fields_to_delete:
            del self.fields[field]

Upvotes: 6

Related Questions