[Solved]-Add dynamic field to django admin model form


You can accomplish what you’re trying by overriding ModelAdmin but you also need to override ModelAdmin.get_fieldsets. This answer might help you out. The OP in the link has a similar problem as well.

Edit: If you don’t want an editable field you can try overriding ModelAdmin.get_readonly_fields. Also check here for more attributes to override.


You can create dynamic fields and fieldset using the form meta class. Sample code is given below. Add the loop logic as per you requirements.

class CustomAdminFormMetaClass(ModelFormMetaclass):
    Metaclass for custom admin form with dynamic field
    def __new__(cls, name, bases, attrs):
        for field in myloop: #add logic to get the fields
            attrs[field] = forms.CharField(max_length=30) #add logic to the form field
        return super(CustomAdminFormMetaClass, cls).__new__(cls, name, bases, attrs)

class CustomAdminForm(six.with_metaclass(CustomAdminFormMetaClass, forms.ModelForm)):
    Custom admin form

    class Meta:
        model = ModelName
        fields = "__all__" 

class CustomAdmin(admin.ModelAdmin):
    Custom admin 

    fieldsets = None
    form = CustomAdminForm

    def get_fieldsets(self, request, obj=None):
        Different fieldset for the admin form
        self.fieldsets = self.dynamic_fieldset(). #add logic to add the dynamic fieldset with fields
        return super(CustomAdmin, self).get_fieldsets(request, obj)

    def dynamic_fieldset(self):
        get the dynamic field sets
        fieldsets = []
        for group in get_field_set_groups: #logic to get the field set group
            fields = []
            for field in get_group_fields: #logic to get the group fields

            fieldset_values = {"fields": tuple(fields), "classes": ['collapse']}
            fieldsets.append((group, fieldset_values))

        fieldsets = tuple(fieldsets)

        return fieldsets


You have to add it to the readonly_fields list.

class SetAdmin(admin.ModelAdmin):
    list_display = ['many other fields', 'show_set_url']
    readonly_fields = ['show_set_url']

    def show_set_url(self, obj):
            return '<a href="#">Set</a>' # render depends on other fields

Relevant documentation.


I had trouble with all of these answers in Django 1.9 for inline models.

Here is a code snippet that accomplished dynamic fields for me. In this example, I’m assuming you already have a modal called ProductVariant which contains a foreign key relationship to a model called Product:

class ProductVariantForm(forms.ModelForm):

class ProductVariantInline(admin.TabularInline):
  model = ProductVariant
  extra = 0

  def get_formset(self, request, obj=None, **kwargs):
    types = ( (0, 'Dogs'), (1, 'Cats'))
        #Break this line appart to add your own dict of form fields.
        #Also a handy not is you have an instance of the parent object in obj
    ProductVariantInline.form = type( 'ProductVariantFormAlt', (ProductVariantForm, ), { 'fancy_select': forms.ChoiceField(label="Animals",choices=types)})
    formset = super( ProductVariantInline, self).get_formset( request, obj, **kwargs)
    return formset

class ProductAdmin(admin.ModelAdmin):
  inlines = (ProductVariantInline, )

My specific use case is ProductVariant has a many to many relationship that should only have limited selections based on business logic grouping of the entries. Thus my need for custom dynamic fields in the inline.

Leave a comment