Django Admin Inlines
Introduction
Django Admin is a powerful built-in feature that automatically generates an admin interface for your models. One of its most useful capabilities is inlines - a feature that allows you to edit related models on the same page. For example, if you have a Book
model with multiple Chapter
objects related to it, inlines let you edit both the book and its chapters from a single admin page.
This feature significantly improves productivity by:
- Reducing navigation between different admin pages
- Providing a clearer view of related data
- Allowing for faster data entry and editing
In this tutorial, we'll explore Django Admin Inlines, understand their types, and see how to implement them in real-world applications.
Understanding Model Relationships
Before diving into inlines, let's quickly refresh our understanding of model relationships in Django:
- One-to-Many (ForeignKey): One model is related to multiple instances of another model
- Many-to-Many (ManyToManyField): Multiple instances of one model relate to multiple instances of another
- One-to-One (OneToOneField): One model instance relates to exactly one instance of another model
Inlines are most commonly used with One-to-Many relationships, though they work with other relationship types as well.
Types of Inlines
Django offers two main types of inlines:
- TabularInline: Displays related objects in a table format (compact, row-based)
- StackedInline: Shows related objects in a stacked form layout (more detailed, form-like)
Let's see how to implement both.
Basic Inline Setup
Let's start with a common example: an Author with multiple Books. First, we'll define our models:
# models.py
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=100)
bio = models.TextField(blank=True)
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')
publication_date = models.DateField()
isbn = models.CharField(max_length=13)
def __str__(self):
return self.title
Now, to display books as inlines within the Author admin page, we need to set up the admin:
# admin.py
from django.contrib import admin
from .models import Author, Book
class BookInline(admin.TabularInline):
model = Book
extra = 1 # Number of empty forms to display
class AuthorAdmin(admin.ModelAdmin):
inlines = [BookInline]
list_display = ('name',)
admin.site.register(Author, AuthorAdmin)
admin.site.register(Book) # Register Book separately too
With this setup, when you edit an Author, you'll see a table at the bottom of the page with all related Books and a form to add new ones.
TabularInline vs StackedInline
Let's compare both inline types using our Author-Book example:
TabularInline (Table Format)
class BookInline(admin.TabularInline):
model = Book
extra = 1
This displays books in a compact table format, with each book as a row and fields as columns. It's ideal when you have many related objects or when the related model has few fields.
StackedInline (Stacked Format)
class BookInline(admin.StackedInline):
model = Book
extra = 1
This displays each book in the same format as a standalone model form - with fields stacked vertically. It's more readable for related models with many fields but takes up more vertical space.
Advanced Inline Configuration
Django provides several options to customize inlines:
Controlling Number of Forms
class BookInline(admin.TabularInline):
model = Book
extra = 2 # Show 2 empty forms for adding new books
max_num = 10 # Maximum number of forms
min_num = 1 # Minimum number of forms
Displaying Specific Fields
class BookInline(admin.TabularInline):
model = Book
fields = ['title', 'publication_date'] # Only show these fields
Adding Fieldsets (for StackedInline)
class BookInline(admin.StackedInline):
model = Book
fieldsets = [
('Basic Information', {'fields': ['title', 'isbn']}),
('Publication Details', {'fields': ['publication_date']})
]
Customizing Display
class BookInline(admin.TabularInline):
model = Book
readonly_fields = ['isbn'] # Make ISBN read-only
show_change_link = True # Add link to change the related object
Real-World Example: Blog System
Let's implement a more complex real-world example: a blog system with posts and comments.
# models.py
from django.db import models
from django.contrib.auth.models import User
class BlogPost(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
published_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Comment(models.Model):
post = models.ForeignKey(BlogPost, on_delete=models.CASCADE, related_name='comments')
author_name = models.CharField(max_length=100)
text = models.TextField()
created_date = models.DateTimeField(auto_now_add=True)
approved = models.BooleanField(default=False)
def __str__(self):
return f"Comment by {self.author_name}"
class Tag(models.Model):
name = models.CharField(max_length=50, unique=True)
posts = models.ManyToManyField(BlogPost, related_name='tags')
def __str__(self):
return self.name
Now, let's set up the admin with inlines:
# admin.py
from django.contrib import admin
from .models import BlogPost, Comment, Tag
class CommentInline(admin.TabularInline):
model = Comment
extra = 1
readonly_fields = ['created_date']
fields = ['author_name', 'text', 'approved', 'created_date']
class TagInline(admin.TabularInline):
model = Tag.posts.through
extra = 1
verbose_name = "Tag"
verbose_name_plural = "Tags"
class BlogPostAdmin(admin.ModelAdmin):
inlines = [CommentInline, TagInline]
list_display = ('title', 'author', 'published_date', 'comment_count')
search_fields = ['title', 'content']
def comment_count(self, obj):
return obj.comments.count()
comment_count.short_description = "Number of comments"
admin.site.register(BlogPost, BlogPostAdmin)
admin.site.register(Comment)
admin.site.register(Tag)
This example demonstrates:
- Multiple inlines on a single admin page (Comments and Tags)
- Using inlines with both ForeignKey and ManyToManyField relationships
- Custom verbose names for better readability
- Read-only fields in inlines
- Custom methods in the admin class
Working with Many-to-Many Relationships
For Many-to-Many relationships, Django uses a special approach. In our example above, we used Tag.posts.through
which refers to the intermediate model Django creates for the Many-to-Many relationship.
Nested Inlines
Sometimes you might want to show multiple levels of related models. While Django's admin doesn't natively support nested inlines, there are third-party packages like django-nested-admin
that enable this functionality.
Here's how you might set it up:
pip install django-nested-admin
Add to your INSTALLED_APPS:
INSTALLED_APPS = [
# ...
'nested_admin',
# ...
]
Then implement nested inlines:
# admin.py
import nested_admin
class SubItemInline(nested_admin.NestedTabularInline):
model = SubItem
extra = 1
class ItemInline(nested_admin.NestedTabularInline):
model = Item
extra = 1
inlines = [SubItemInline]
class CategoryAdmin(nested_admin.NestedModelAdmin):
inlines = [ItemInline]
admin.site.register(Category, CategoryAdmin)
Best Practices for Inlines
-
Use TabularInline for compact data: For related objects with few fields, use TabularInline to conserve space
-
Use StackedInline for complex forms: When related objects have many fields, StackedInline provides better readability
-
Limit the number of inlines: Too many inlines on one page can make the form slow and unwieldy. Use
max_num
to limit them -
Consider performance: Inlines load all related objects at once, which can be slow if there are many. Consider using filters or limiting displayed fields
-
Use fieldsets to organize: Especially with StackedInline, use fieldsets to group related fields
-
Consider read-only fields: For important fields that shouldn't be edited in the inline context
Summary
Django Admin Inlines are a powerful feature that lets you edit related models from a single admin page, improving workflow and data entry efficiency. We've covered:
- Basic inline setup with TabularInline and StackedInline
- Advanced configuration options
- Real-world examples with different relationship types
- Best practices for using inlines effectively
By leveraging inlines, you can create a much more intuitive and efficient admin interface for your Django projects. This is particularly useful when working with models that have strong logical relationships.
Additional Resources
- Django Official Documentation on Inlines
- Django Nested Admin - For nested inlines
- Django Admin Cookbook - Advanced admin customizations
Exercises
-
Create a simple Product and ProductImage model where each Product can have multiple images, and implement inline editing.
-
Extend the blog system example by adding Categories and implementing both TabularInline and StackedInline to compare their layouts.
-
Try implementing a nested inline structure using django-nested-admin for a hierarchical data model (e.g., Courses > Modules > Lessons).
-
Create a custom inline that validates related models (hint: you'll need to override the
clean()
method).
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)