A question that pops up every once in a while is how to create Django admin forms dynamically.

This is actually trivial, thanks to the fact that Python has closures. But the fact that it is so simple may not be obvious to everybody, so I am documenting it here for future reference.

Let's look at a simple example. One reason to use a dynamically constructed ModelForm in Django's admin interface is to filter the possible values of a dropdown widget for a ModelChoiceField by some criteria that is only known at runtime, such as the current user. The way to do this is to use a simple factory function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def myadminform_factory(user):
    class MyForm(forms.ModelForm):
        my_field = forms.ModelChoiceField(
            queryset=SomeModel.objects.filter(user=user)
        )
    return MyForm


class MyAdmin(admin.ModelAdmin):

    def get_form(self, request, obj=None, **kwargs):
        kwargs['form'] = myadminform_factory(request.user)
    return super(MyAdmin, self).get_form(request, obj, **kwargs)

The ModelAdmin's get_form method has access to the request, so we can use it to do our customization. One thing to note is that this method is badly named. It is responsible for creating the form class, not the form instance. We just create our custom dynamic form class here, and then pass it on to the superclass' method, which will use our form class as a base class for its work.

For further details, see the excellent Django documentation.