Django Inline Admin with examples in detail

In this tutorial, we will learn how to add Inlines or inline models in Django admin. You can update a number of identical models on the same page using a Django inline model admin. In essence, it enables you to bulk edit a number of things at once.

What is Django Inline Admin?

The Django admin interface has the ability to edit models on the same page as a parent model. These are called inlines.

Django offers two InlineModelAdmin subclasses, and they are:

  1. TabularInline
  2. StackedInline

The only distinction between these two is the template that was utilized to render them.

Why we need Django inlines:

To allow a user to create and update related via Foreign Key objects from the create/update views of a referenced object, all on one page.

Let's move toward coding. We have 3 models. Product, Images, and Variants. Images and Variants have foreign relations with the Product model.

# models.py

from django.db import models
from django.utils.safestring import mark_safe


class Product(models.Model):
    title = models.CharField(max_length=150)
    short_description = models.TextField(max_length=100)

    def __str__(self):
        return self.title


class Image(models.Model):
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, null=True
        )
    image = models.ImageField(blank=True, upload_to='images')

    def __str__(self):
        return self.product.title

    def image_tag(self):
        if self.image.url is not None:
            return mark_safe('<img src="{}" height="50"/>'.format(self.image.url))
        else:
            return ""



class Variant(models.Model):
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE
        )
    size = models.CharField(max_length=100)
    quantity = models.PositiveIntegerField(default=1)
    price = models.DecimalField(max_digits=12, decimal_places=2)

    def __str__(self):
        return self.product.title

After running migrations, register your model in admin panel.

# admin.py

from django.contrib import admin

from .models import (
    Product, Image, Variant
)

admin.site.register(Product)
admin.site.register(Image)
admin.site.register(Variant)

Now when you go to the admin panel you will see 3 models. And our product model will look like this:

But what do I want? I want to edit the Product, Images, and Variants model all on one page (Change Product page) and we can do this by adding Images and Variant Inlines to Product Admin model.

Now let's add the Image and Variant Inlines. Go to admin.py and add the following code.

# admin.py

from django.contrib import admin

from .models import (
    Product, Image, Variant
)

admin.site.register(Image)
admin.site.register(Variant)


class ProductImageInline(admin.TabularInline):
    model = Image
    readonly_fields = ('id', 'image_tag',)
    extra = 1
    

class ProductVariantInline(admin.TabularInline):
    model = Variant
    readonly_fields = ('id',)
    extra = 1


@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    inlines = [ProductVariantInline, ProductImageInline]

The code is very simple. We have ProductImageInline and ProductVariantInline classes and then we are registering these two inlines in our parent model i.e ProductAdmin.

Now go to the admin panel. And you will see image inlines and variant inlines are added to our product model admin.

That's great. Now we can edit the product and all images and variants that are linked (via foreign key) to the product model on one page.

We have added inlines using simple options but there are many advance options we can add to our inlines.

InlineModelAdmin Options:

The InlineModelAdmin class adds or customizes the following options:

*Note: We are focusing on Variant Inline admin (ProductVariantInline) and will implement all these options in ProductVariantInline class.

InlineModelAdmin.model: The model which the inline is using. This is required. In our case, it is model = Variant

class ProductVariantInline(admin.TabularInline):
    model = Variant

InlineModelAdmin.fk_name: The name for the foreign key on the model. Most of the time, this will be taken care of automatically, but if there are many foreign keys to the same parent model, fk name is required.

class ProductVariantInline(admin.TabularInline):
    model = Variant
    fk_name = "product" #optional

InlineModelAdmin.form: The value for form defaults to ModelForm. But you can also add your own form by doing some customization like adding placeholders, different CSS classes, and form validations.

Explanation: How to add custom form with validations in django inline admin

InlineModelAdmin.classes: A list or tuple containing extra CSS classes to apply to the fieldset that is rendered for the inlines. Defaults to None. As with classes configured in fieldset, inlines with a collapse class will be initially collapsed and their header will have a small “show” link.

class ProductVariantInline(admin.TabularInline):
    model = Variant
    extra = 1
    classes = ('collapse', )

InlineModelAdmin.extra: This regulates how many more forms, in addition to the initial forms, the formset displays. to 3 by default.

class ProductVariantInline(admin.TabularInline):
    model = Variant
    extra = 1

InlineModelAdmin.can_delete: specifies whether inline items may be deleted within the inline. Default to True. If you don't want to delete inlines you can set it to False.

class ProductVariantInline(admin.TabularInline):
    model = Variant
    can_delete = False

InlineModelAdmin.show_change_link: Specifies whether or not inline objects that can be changed in the admin have a link to the change form. Defaults to False.

class ProductVariantInline(admin.TabularInline):
    model = Variant
    show_change_link = True

readonly_fields: You can also specify readonly fields.

class ProductVariantInline(admin.TabularInline):
    model = Variant
    readonly_fields = ('id', 'price',)

InlineModelAdmin.has_add_permission(requestobj): Should return True if adding an inline object is permitted, False otherwise. obj is the parent object being edited or None when adding a new parent.

Returning this to False will disable the add inlines option.

class ProductVariantInline(admin.TabularInline):
    model = Variant
    extra = 1

    def has_add_permission(self, request, obj):
        return False

InlineModelAdmin.has_change_permission(requestobj=None): Should return True if editing an inline object is permitted, False otherwise. obj is the parent object being edited.

Returning this function to False will not allow to change the inlines.

class ProductVariantInline(admin.TabularInline):
    model = Variant
    extra = 1

    def has_change_permission(self, request, obj=None):
        return False

 

InlineModelAdmin.has_delete_permission(requestobj=None): Should return True if deleting an inline object is permitted, False otherwise. obj is the parent object being edited.

Returning this functions to False will disable the delete inline checkboxes.

class ProductVariantInline(admin.TabularInline):
    model = Variant
    extra = 1

    def has_delete_permission(self, request, obj=None):
        return False

I can't cover all options in one article. You can find more options in documentation. like max_num, min_num etc.

StackedInlines.

The difference between Tabular and stacked inline is only the template.

class ProductImageInline(admin.StackedInline):
    model = Image
    readonly_fields = ('id', 'image_tag',)
    extra = 1

StackedInline will give inlines in this format.

If this article is helpful then you can support us by buying me a coffee.

Related Article:

Django Inline Formset Factory with Examples.

I would greatly appreciate it if you subscribe to my YouTube channel, Let's Code More

 ⋅  5 comments have been posted.
    Jan. 6, 2024, 6:52 a.m. - Stranger  
    It was very helpful and it is well explained aswell, very good work Areeba. Keep it up
    Reply
    March 20, 2023, 1:12 p.m. - Faaiz Sultan  
    How can i Paginate Inline admin Forms?
    Reply
    Dec. 6, 2022, 9:45 a.m. - Verstov  
    Hello, thank you for this article! How can I validate these form? For example: each product must have 2 images or more
    Reply
    Dec. 6, 2022, 10:29 a.m. - Areeba Seher moderator  
    You're welcome. Please visit the following links for your query. 1) https://stackoverflow.com/questions/877723/inline-form-validation-in-django 2) https://www.letscodemore.com/blog/how-to-set-atleast-one-inline-form-required-in-django-inline-formset/
    Reply
    Dec. 6, 2022, 6:02 p.m. - Verstov  
    thanks, but this is not exactly what I need :( Is there way to check all of the values before save? For example - validate that at least one of product size is 'S' Actually I'm making a quiz with `admin.TabularInline `. And I need to validate that at list one answer marked as correct. How can I validate it in Django admin? If it is not possible, how can I validate it using forms? It looks so easy, but I can't find the answer

Your comment

Required for comment verification
claps