I recently came across the need to let admins create/edit specific objects from Django admin with an inline formset (nested forms).

In Rails, this can be accomplished by simply doing this.

accepts_nested_attributes_for :model

Things are a little bit different in Django. As opposed to Rails, Django provides an admin interface by default but getting the same to work in a nested way isn’t very obvious.


class Provider(models.Model):
	name  = models.CharField(max_length=100)
 	slug  = models.CharField(max_length=100, null=True, blank=True)
 	url = models.CharField(max_length=255, null=True, blank=True)
 	image_url = models.CharField(max_length=255, null=True, blank=True)

class ProviderConfig(models.Model):
	provider = models.ForeignKey(Provider)
	...# regular django model fields

The problem statement is simple, I need to show and create ProviderConfig together with the Provider. I boiled a fresh pot of brew and started digging. A couple of hours later I was finally able to wrap my head around this.

First step in achieving the desired behaviour is to define a form (one that is to be nested) for ProviderConfig and add the following snippet in admin.py.


class ProviderConfigInline(admin.TabularInline):
    model = ProviderConfig
        extra = 5  #This says the number of forms to be show as default, here it gives 5
        ProviderConfig forms

Inline formsets in django forms are defined using inlines which can be a TabularInline and/or StackedInline Once we have our Inline form defined, we need to hook it to the ProviderAdmin form that is achieved by adding the following to admin.py.


class ProviderAdmin(admin.ModelAdmin):
    fieldsets = [('Provider', {'fields': ['name', 'slug', 'url', 'image_url']})]

    inlines = [ProviderConfigInline]

In the snippet above, inlines is where we define the form that is to be nested, in our case ProviderConfigInline . The attribute fieldsets lets you control the model fields to be displayed on that model’s admin form/view.

Tying this all together we have the following.


from django.contrib import admin
from apps.app1.models import *

class ProviderConfigInline(admin.TabularInline):
    model = ProviderConfig
    extra = 5  # This says the number of forms to be show as default, here it gives 5 ProviderConfig forms

class ProviderAdmin(admin.ModelAdmin):
    fieldsets = [('Provider', {'fields': ['name', 'slug', 'url', 'image_url', 'type', 'weight', 'active']})]

    inlines = [ProviderConfigInline]

admin.site.register(Provider, ProviderAdmin)

We now have Provider and ProviderConfig as nested forms in Django admin. More details at django-docs.