Dynamically add a field to a model form

Ok, as someone who has been known to abuse the admin on more than one occasion, I did some digging. I can’t really summarize everything here, because a lot of it is still a little hazy to me, but…

in admin.py

class MyAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, change=False, **kwargs):
        return MyForm

in forms.py

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel
        exclude = []

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # The following dynamically add three fields to the model form
        for x in ['e1', 'e2', 'e3']:
            self.base_fields[x] = forms.CharField()
            self.fields[x] = forms.CharField()

    def save(self, *args, **kwargs):
        # The following demonstrates that the three extra fields are passed into cleaned_data
        print(self.cleaned_data)
        return super().save(*args, **kwargs)

Use as your own risk. No warranty, guarantee, or assurance applies to any of the above. All disclaimers apply. If this causes your computer to melt, don’t blame me.

From the docs at https://docs.djangoproject.com/en/3.0/ref/forms/api/:

Beware not to alter the base_fields attribute because this modification will influence all subsequent ContactForm instances within the same Python process.

so this might not be as dynamic as desired. (Of course, I’m one of those that believes the admin facility should be restricted to as few people as possible. If you’re using this in any situation where you might be expecting multiple people to be doing this at the same time, then I would argue you’re misusing the admin. In the normal/routine case, the admin wouldn’t be any part of your user-facing site, and so you could perform these dynamic modifications from within your view.)

Ken

1 Like