Django admin inlines allow you to edit related models on the same page as the parent model in the admin interface.
They're useful when you have parent-child relationships between models and want to manage them together.
from django.contrib import admin
class OrderItemInline(admin.TabularInline): # or admin.StackedInline for a different layout
model = OrderItem
extra = 1 # number of empty forms to display
raw_id_fields = ('product',) # adds a lookup widget for product selection
class OrderAdmin(admin.ModelAdmin):
list_display = ('id', 'customer', 'created_dt', 'status')
list_filter = ('status',)
readonly_fields = ('created_dt', 'completed_dt')
inlines = [OrderItemInline]
admin.site.register(Order, OrderAdmin)
TabularInline example:
StackedInline example:
Add change link to Inline Admin:¶
Let's add another inline for orders and place it into the CustomerAdmin
.
First let's add show_change_link = True
and it will display a link to the Order.
class LatestOrdersInline(admin.TabularInline):
model = Order
fields = ("id", "created_dt", "status")
readonly_fields = ("id", "created_dt", "status")
extra = 0
ordering = ("-created_dt",)
show_change_link = True
class CustomerAdmin(admin.ModelAdmin):
list_display = (
"first_name",
"last_name",
"phone",
"id",
)
inlines = [LatestOrdersInline]
admin.site.register(Customer, CustomerAdmin)
How to do Django admin inline Queryset limit¶
You can override get_queryset(request)
method in admin.TabularInline
and admin.StackedInline
.
Unfortunately, if you make a slice like this super().get_queryset(request).order_by('-id')[:10]
it would lead to an error:
TypeError at /admin/myapp/customer/1/change/ Cannot filter a query once a slice has been taken.
So what you have to do is to make two queries:
- One to get IDs of the desired records
- another to fetch records with IDs from the first query.
class LatestOrdersInline(admin.TabularInline):
model = Order
fields = ("id", "created_dt", "status")
readonly_fields = ("id", "created_dt", "status")
extra = 0
ordering = ("-created_dt",)
show_change_link = True
verbose_name = 'Latest Orders'
def get_queryset(self, request):
ids = (
super()
.get_queryset(request)
.order_by("-created_dt")
.values_list("id", flat=True)[:5]
)
qs = super().get_queryset(request).filter(id__in=ids).order_by("-created_dt")
return qs
class CustomerAdmin(admin.ModelAdmin):
list_display = (
"first_name",
"last_name",
"phone",
"id",
)
inlines = [LatestOrdersInline]
admin.site.register(Customer, CustomerAdmin)
Also we have changed the name of the Django Admin Inline block using verbose_name
to "Latest Orders"