Belajar Django - Django Admin
Episode 8 of 27

Belajar Django - Django Admin

Mengaktifkan dan mengkustomisasi Django Admin sebagai CMS production: ModelAdmin dengan list_display, list_filter, search_fields, dan list_editable, inline untuk relasi, custom actions, serta hardening akses admin agar aman di produksi.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Salah satu "batteries-included" paling terkenal yang kita bahas di episode 1 adalah Django Admin — panel CRUD otomatis yang lahir dari model. Di episode 7 database sudah punya tabel; sekarang kita menaiki layer di atasnya: mengubah admin bawaan menjadi CMS yang benar-benar nyaman dipakai editor dan aman di produksi.

Mengapa topik ini penting? Karena admin yang baik adalah produk tersendiri. list_display, filter, search, inline, dan custom actions adalah perbedaan antara "panel yang bisa dipakai" dan "panel yang bikin editor frustrasi". Ditambah, admin adalah salah satu permukaan serangan paling populer — jadi hardening-nya wajib dipahami.

Mengaktifkan dan Login Pertama

Admin sudah aktif sejak startproject (terdaftar di INSTALLED_APPS dan urls.py). Buat superuser lalu masuk:

Buat superuser dan akses admin
python manage.py createsuperuser
python manage.py runserver

Buka http://127.0.0.1:8000/admin, login dengan kredensial tadi. Kalian akan melihat model Users, Groups, dan — setelah mendaftarkan model di admin.py — model blog kita.

Pythonblog/admin.py - daftarkan model dasar
from django.contrib import admin
 
from .models import Category, Post, Tag
 
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
    list_display = ("name", "slug")
 
@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
    list_display = ("name",)
 
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    pass

@admin.register(Model) menggantikan admin.site.register(Model, ModelAdmin) dan menjaga pasangan model-admin tetap dekat. Tanpa registrasi, model tidak muncul di admin.

list_display menentukan kolom yang tampil di halaman daftar. Inilah pengaturan yang paling terasa bagi editor:

Pythonblog/admin.py - PostAdmin lengkap
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ("title", "status", "category", "author", "created_at")
    list_filter = ("status", "category", "created_at")
    search_fields = ("title", "slug", "body")
    list_editable = ("status",)
    list_per_page = 25
    date_hierarchy = "created_at"
    ordering = ("-created_at",)
  • list_filter menambah sidebar filter — panel di kanan untuk memfilter berdasarkan status, category, atau tanggal.
  • search_fields membuat kotak pencarian; field CharField/TextField menghasilkan pencarian LIKE, sementara FK menghasilkan pencarian id.
  • list_editable mengizinkan edit langsung dari halaman daftar — sangat nyaman untuk mengubah status banyak post tanpa membuka halaman detail.
  • date_hierarchy menghasilkan navigasi "drill-down" per tahun/bulan/hari.

Tip

Jangan terlalu banyak list_editable — kolom editable dihitung dalam satu save, dan setiap kolom yang bukan list_display atau list_editable tetap tampil sebagai link. Untuk status massal, custom action (di bawah) sering lebih tepat daripada list_editable.

Inline: Kelola Relasi dari Halaman Induk

Inline memungkinkan mengelola relasi banyak-ke-satu langsung dari halaman model induk. Untuk komentar dalam halaman post:

Pythonblog/admin.py - inline
from .models import Comment
 
class CommentInline(admin.StackedInline):
    model = Comment
    extra = 0
 
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    inlines = [CommentInline]

StackedInline menampilkan form bertumpuk vertikal; TabularInline menampilkan tabel ringkas. extra = 0 mencegah tiga form kosong muncul default — hanya form yang benar-benar diisi yang ditambahkan.

Custom Actions

Actions adalah operasi batch yang dijalankan pada baris yang dipilih di halaman daftar. Django punya aksi bawaan "delete selected"; kita tambahkan aksi publish/unpublish:

Pythonblog/admin.py - custom actions
@admin.action(description="Publish post terpilih")
def publish_posts(modeladmin, request, queryset):
    updated = queryset.update(status="published")
    modeladmin.message_user(request, f"{updated} post dipublikasikan.")
 
@admin.action(description="Tarik kembali post terpilih")
def unpublish_posts(modeladmin, request, queryset):
    queryset.update(status="draft")
 
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ("title", "status", "category", "author", "created_at")
    actions = [publish_posts, unpublish_posts]

queryset.update(...) menghasilkan satu query UPDATE — bukan loop save. @admin.action(description=...) menggantikan atribut actions yang lama dan lebih eksplisit. Action menerima tiga argumen: modeladmin, request, dan queryset yang terpilih.

Override Method untuk Validasi Admin

Kadang logika harus berbeda antara admin dan form publik. Override method model yang dipanggil admin:

Pythonblog/admin.py - override save_model
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ("title", "status", "author", "created_at")
 
    def save_model(self, request, obj, form, change):
        if not change:
            obj.author = request.user
        super().save_model(request, obj, form, change)

save_model di-override agar author otomatis diisi user yang sedang login saat membuat post baru — mengikuti prinsip "audit trail" tanpa memaksa editor memilih nama sendiri.

Hardening Admin di Produksi

Admin adalah permukaan serangan bernilai tinggi. Empat langkah minimum sebelum produksi:

  1. Jangan pernah expose /admin/ dengan nama default — ganti prefix di urls.py:
Pythondevblog/urls.py - sembunyikan admin
from django.contrib import admin
from django.urls import path
 
urlpatterns = [
    path("secure-console/", admin.site.urls),
]
  1. Batasi akses via middleware atau reverse proxy — admin hanya boleh diakses dari IP kantor/VPN. Ini kita kerjakan di episode 18 dan 23.

  2. Matikan di environment non-staf — jika app tidak butuh admin di produksi, jangan daftarkan URL admin di urls.py produksi sama sekali.

  3. Pakai login yang kuat — aktifkan rate limiting login dan 2FA. Implementasinya kita bahas di episode 19 dan 20.

Warning

django.contrib.admin memakai model User bawaan yang di-refer oleh auth. Jika kalian berencana memakai custom user model (best practice di episode 10), keputusan itu harus dibuat sebelum migrasi pertama. Mengganti user model setelah database berisi data adalah operasi yang sangat menyakitkan.

Penutup

Inti yang harus dibawa pulang:

  • Daftarkan model via @admin.register; model tak terdaftar tak muncul di admin.
  • list_display, list_filter, search_fields, dan list_editable membuat daftar post produktif.
  • Inline mengelola relasi dari halaman induk; extra = 0 mencegah form kosong default.
  • Custom actions (@admin.action) memberi operasi batch sekali query.
  • Override save_model untuk logika khusus admin (misal set author otomatis).
  • Hardening: ganti path admin, batasi IP, dan matikan di produksi bila tak perlu.

Di episode 9 selanjutnya kita melengkapi sisi input data: Forms & Validation — Form dan ModelForm, validasi bersih dan validasi per-field, widgets, error rendering, serta form komentar dengan proteksi CSRF. Admin selesai, sekarang giliran form publik!

Belajar Django - Django Admin | Belajar Django