[Fixed]-Django forms exclude fields on init rather than in the meta class


You can modify the self.fields list after calling super.


You should use modelform_factory to create the form on the fly and pass in the fields you want to exclude.

def django.forms.models.modelform_factory   (       
    form = ModelForm,
    fields = None,
    exclude = None,
    formfield_callback = lambda f: f.formfield()     

So something like

modelform_factory(MyModel, MyModelForm, exclude=('name',))


You should use self._meta instead of self.Meta, because the ModelForm.__new__ method get attributes form self.Meta and puts them into self._meta.


Related, to exclude fields from a sub-class, I have extended the ModelForm class like so:

 class ModelForm(djangoforms.ModelForm):
   def __init__(self, *args, **kwargs):
     super(ModelForm, self).__init__(*args, **kwargs)

     meta = getattr(self, 'Meta', None)
     exclude = getattr(meta, 'exclude', [])

     for field_name in exclude:
       if field_name in self.fields:
         del self.fields[field_name]


I made like this:

class Meta:
    exclude = [field.label for field in Fields.objects.filter(visible=False)] + ['language', 'created_at']


Just to note: if your form is called from a ModelAdmin class, just create a get_form method for the ModelAdmin:

def get_form(self, request, obj=None, **kwargs):
    exclude = ()

    if not request.user.is_superuser:
        exclude += ('field1',)

    if obj:
        exclude += ('field2',)

    self.exclude = exclude
    return super(ProfessorAdmin, self).get_form(request, obj, **kwargs)

PS: change ProfessorAdmin by the method “owner” class.


Leave a comment