python 37 lines · 7 steps

Custom columns in the Django admin

Register a model with the Django admin and add computed, styled columns using @admin.display methods.

Explained by highlit
1from django.contrib import admin
2from django.utils import timezone
3from django.utils.html import format_html
4 
5from .models import Subscription
6 
7 
8@admin.register(Subscription)
9class SubscriptionAdmin(admin.ModelAdmin):
10 list_display = ("customer", "plan", "status_badge", "days_remaining", "is_active")
11 list_select_related = ("customer", "plan")
12 ordering = ("-created_at",)
13 
14 @admin.display(description="Status", ordering="status")
15 def status_badge(self, obj):
16 colors = {
17 "active": "#2e7d32",
18 "trialing": "#0277bd",
19 "past_due": "#f9a825",
20 "canceled": "#c62828",
21 }
22 return format_html(
23 '<span style="color:{}; font-weight:600">{}</span>',
24 colors.get(obj.status, "#616161"),
25 obj.get_status_display(),
26 )
27 
28 @admin.display(description="Days left")
29 def days_remaining(self, obj):
30 if obj.current_period_end is None:
31 return "\u2014"
32 delta = (obj.current_period_end - timezone.now()).days
33 return max(delta, 0)
34 
35 @admin.display(description="Active", boolean=True)
36 def is_active(self, obj):
37 return obj.status in ("active", "trialing")
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1The @admin.display decorator turns a method into a virtual column with its own header, sort key, and boolean icon.
  2. 2format_html safely interpolates values into markup so admin cells can carry styling without XSS risk.
  3. 3list_select_related batches related-object lookups to keep custom columns from firing N+1 queries.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Custom columns in the Django admin — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code