When a model has 10–15 fields, its edit page in Django admin becomes one endless column: title, slug, content, category, publish date, and status flags all jumbled together. The fix is fieldsets to group fields into titled, collapsible sections, combined with prepopulated_fields so the slug fills itself in from the title without typing. Both only need to be declared in ModelAdmin.
The Problem
By default, Django admin shows every field of a model in declaration order, stacked in a single column. For an article model with many fields, the edit page drags on forever: important fields like the title sit next to rarely used ones like the publish date. Worse, the slug field usually has to be typed by hand — a wrong format, a duplicate of an old slug, or a forgotten value all cause errors on save.
# admin.py — default: every field stacked in one long column from django.contrib import admin from .models import Article @admin.register(Article) class ArticleAdmin(admin.ModelAdmin): list_display = ("title", "category", "is_published") The Solution
Declare fieldsets to split the form into groups, and prepopulated_fields so the slug fills in from the title as you type:
# admin.py from django.contrib import admin from .models import Article @admin.register(Article) class ArticleAdmin(admin.ModelAdmin): list_display = ("title", "category", "is_published") fieldsets = ( (None, { "fields": ("title", "slug"), }), ("Content", { "fields": ("category", "content"), }), ("Publishing", { "classes": ("collapse",), "fields": ("is_published", "published_at"), }), ) prepopulated_fields = {"slug": ("title",)} Each tuple in fieldsets holds a group title and a describing dict: a first group with title None shows no separate heading. The “Publishing” group has "classes": ("collapse",), so it starts collapsed — rarely used fields stop taking up space. prepopulated_fields takes a dict like {"slug": ("title",)}: as you type the title, the admin’s JavaScript generates the slug following the slugify standard, for example “My New Article” becomes my-new-article.
Three things to watch. First, never declare both fields and fieldsets in the same ModelAdmin — Django raises a configuration error. Second, prepopulated_fields only fills the slug in while it is empty, so a slug that is already saved is never overwritten when you edit the title later. Third, slugify strips accents by default, so generated slugs are always clean and URL-safe.
Apply It to Your Project
Open the admin.py of the app with the model that has the most fields, group the fields the way data is really entered: key information first, content in the middle, settings and status in a collapsed group at the end. Add prepopulated_fields to every model that has a SlugField next to a name or title field. After saving, reopen the edit page and check: the rarely used group must be collapsed, and the slug must generate correctly when creating a new record.
Related Posts
Django admin: khóa field không cho sửa bằng readonly_fields trong 5 phút
Django Admin Inlines: Edit Child Records on the Parent Detail Page in 5 Minutes
Frequently Asked Questions
How are fieldsets different from fields?
fields only lists field order in a single column, while fieldsets splits the form into groups with their own titles and supports CSS classes like collapse or wide. Use fields when you only need to reorder; use fieldsets when you want grouping and collapsing.
Does prepopulated_fields overwrite a saved slug?
No. The admin JavaScript only fills the slug in while the slug field is empty, which is normally when creating a new record. When you edit an old record, the slug stays as it is even if you change the title — edit the slug by hand if you want it changed.
What happens to accented characters in slugs?
slugify strips accents by default, so “Bài viết mới” becomes bai-viet-moi. If you want to keep accents in slugs, pass allow_unicode=True to slugify in save(), but accented URLs are error-prone when shared, so the default accent-stripping is the safer choice.
Can fieldsets be used together with readonly_fields?
Yes. A read-only field is declared normally inside fieldsets, and Django shows its value instead of an input box. This is handy when you want to group locked fields like the creation date into the collapsed group at the bottom of the page.
References
Django documentation — ModelAdmin.fieldsets: https://docs.djangoproject.com/en/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets
Django documentation — ModelAdmin.prepopulated_fields: https://docs.djangoproject.com/en/5.2/ref/contrib/admin/#django.contrib.admin.ModelAdmin.prepopulated_fields
Haki Benita — Things You Must Know About Django Admin As Your App Gets Bigger: https://hakibenita.com/things-you-must-know-about-django-admin-as-your-app-gets-bigger
