Django sudah memberi halaman admin gratis sejak awal — kamu tinggal bikin superuser, dan model yang terdaftar langsung bisa dikelola. Tapi tampilan bawaannya polos: satu kolom teks panjang, tanpa filter, tanpa pencarian. Begitu data makin banyak, halaman admin bawaan justru bikin kerjaan makin lambat.

Bagian terbaiknya, Django Admin bisa dikustomisasi lewat satu file admin.py tanpa menulis HTML sendiri. Di bawah ini kamu mengubah halaman admin bawaan jadi panel pengelolaan data yang benar-benar bisa dipakai sehari-hari.

Mendaftarkan Model ke Admin

Mulai dari model sederhana. Anggap kamu punya model Artikel dan Kategori seperti ini:

python
# models.py
from django.db import models


class Kategori(models.Model):
    nama = models.CharField(max_length=100)
    slug = models.SlugField(unique=True)

    def __str__(self):
        return self.nama


class Artikel(models.Model):
    judul = models.CharField(max_length=200)
    slug = models.SlugField(unique=True)
    kategori = models.ForeignKey(Kategori, on_delete=models.CASCADE, related_name="artikel")
    isi = models.TextField()
    is_published = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.judul

Cara paling cepat menampilkan keduanya di admin adalah mendaftarkannya langsung:

python
# admin.py
from django.contrib import admin
from .models import Artikel, Kategori

admin.site.register(Kategori)
admin.site.register(Artikel)

Sebelum bisa masuk, buat superuser dulu kalau belum ada:

python manage.py createsuperuser

Setelah itu buka /admin/, login, dan kedua model sudah muncul di sidebar. Tapi daftar artikel hanya menampilkan __str__-nya — satu kolom teks yang tidak membantu sama sekali saat ada ratusan baris. Kita perbaiki mulai dari sini.

list_display: Menentukan Kolom yang Tampil

python
# admin.py
from django.contrib import admin
from .models import Artikel


@admin.register(Artikel)
class ArtikelAdmin(admin.ModelAdmin):
    list_display = ("judul", "kategori", "is_published", "created_at")

@admin.register menggantikan admin.site.register sekaligus menempelkan class konfigurasinya. Sekarang daftar artikel punya empat kolom yang bisa diklik untuk mengurutkan. Untuk kolom hasil perhitungan, buat method di ModelAdmin:

python
@admin.register(Artikel)
class ArtikelAdmin(admin.ModelAdmin):
    list_display = ("judul", "kategori", "jumlah_kata", "is_published")

    @admin.display(description="Jumlah Kata", ordering="isi")
    def jumlah_kata(self, obj):
        return len(obj.isi.split())

Dekorator @admin.display mengatur judul kolom sekaligus mengaktifkan sorting. Tanpa argumen ordering, kolom hasil hitungan seperti ini tidak bisa diurutkan.

Kolom yang membaca nilai lewat relasi bisa memicu query ekstra per baris (N+1) di daftar admin. Kalau datamu mulai banyak, override get_queryset lalu tambahkan select_related atau prefetch_related sesuai relasinya.

list_filter, search_fields, dan list_editable

python
@admin.register(Artikel)
class ArtikelAdmin(admin.ModelAdmin):
    list_display = ("judul", "kategori", "is_published", "created_at")
    list_filter = ("is_published", "kategori", "created_at")
    search_fields = ("judul", "isi")
    list_editable = ("is_published",)
    date_hierarchy = "created_at"
    list_per_page = 25

list_filter menambahkan panel filter di sisi kanan, search_fields menambahkan kotak pencarian yang cocok untuk CharField dan TextField, sedangkan list_editable memungkinkan kamu mencentang is_published langsung dari halaman daftar tanpa membuka form. date_hierarchy otomatis membuat navigasi drill-down per tanggal di atas daftar.

Inline Form untuk Relasi

Sering kali kamu mengisi artikel sekaligus kategori yang belum ada. Daripada pindah-pindah halaman, tampilkan kategori langsung di dalam form artikel lewat inline:

python
class KategoriInline(admin.TabularInline):
    model = Kategori
    extra = 1


@admin.register(Artikel)
class ArtikelAdmin(admin.ModelAdmin):
    list_display = ("judul", "kategori", "is_published", "created_at")
    inlines = [KategoriInline]

Pendekatan ini masuk akal kalau relasinya mengarah dari artikel ke kategori (ForeignKey di Artikel). Kalau justru kamu ingin mengelola banyak artikel dari halaman kategori, balik arahnya: daftarkan inline Artikel di KategoriAdmin. Gunakan StackedInline untuk tampilan yang lebih vertikal dan lebar.

Custom Action Massal

python
@admin.register(Artikel)
class ArtikelAdmin(admin.ModelAdmin):
    list_display = ("judul", "kategori", "is_published", "created_at")
    actions = ["publish_semua"]

    @admin.action(description="Terbitkan artikel terpilih")
    def publish_semua(self, request, queryset):
        updated = queryset.update(is_published=True)
        self.message_user(request, f"{updated} artikel diterbitkan.")

Action muncul di dropdown di atas daftar. Pilih beberapa baris lewat checkbox, klik action, dan queryset.update() menjalankan satu query SQL untuk semua baris sekaligus.

Selalu pakai queryset.update(), bukan loop yang memanggil obj.save() satu per satu. Kalau kamu punya method save() custom dengan logika tambahan, loop memang diperlukan — tapi pahami dulu itu jauh lebih lambat untuk ribuan baris.

Mempercantik Header Admin

python
# admin.py
from django.contrib import admin

admin.site.site_header = "BengkelKode CMS"
admin.site.site_title = "Admin BengkelKode"
admin.site.index_title = "Panel Pengelolaan Konten"

Tiga baris itu mengganti judul halaman, teks tab browser, dan judul dashboard. Untuk autocomplete dropdown ForeignKey saat datanya banyak, tambahkan autocomplete_fields = ("kategori",) di ArtikelAdmin plus search_fields di KategoriAdmin.

Kalau kamu masih baru dengan Django, mulai dari Membuat Website Pertamamu dengan Django untuk paham alur project-nya. Model dan relasi yang dipakai di sini dijelaskan lebih dalam di panduan Django Models & Migrations. Dan begitu daftar admin kamu mulai lambat karena relasi, cek teknik optimasi QuerySet untuk basmi N+1 lewat select_related dan prefetch_related.