When working on a content-heavy Django project, I found myself constantly repeating the same code in admin.py — list_display, search_fields,
and more.
I thought: what if Django could figure this out on its own?
So I built a reusable utility that does exactly that.
Let me walk you through it — and give you the full code so you can plug it into your own project.
The Utility: auto_admin.py
Save this file as auto_admin.py
in your project (e.g., inside a utils/
or core/
folder).
from django.contrib import admin
from django.db import models
def generate_auto_admin(model):
meta = model._meta
fields = [f for f in meta.fields]
list_display = [f.name for f in fields if not isinstance(f, models.TextField)]
search_fields = [f.name for f in fields if isinstance(f, (models.CharField, models.TextField))]
list_filter = [f.name for f in fields if isinstance(f, (models.BooleanField, models.DateField, models.ForeignKey))]
ordering = ['-id'] if any(f.name == 'id' for f in fields) else None
readonly_fields = [f.name for f in fields if not f.editable]
prepopulated_fields = {}
for f in fields:
if isinstance(f, models.SlugField):
for src in fields:
if isinstance(src, models.CharField) and src.name != f.name:
prepopulated_fields[f.name] = (src.name,)
break
date_hierarchy = next((name for name in ['created_at', 'published_at', 'date'] if name in [f.name for f in fields]), None)
admin_attrs = {
"list_display": list_display,
"search_fields": search_fields,
"list_filter": list_filter,
"ordering": ordering,
"readonly_fields": readonly_fields,
"date_hierarchy": date_hierarchy,
}
if prepopulated_fields:
admin_attrs["prepopulated_fields"] = prepopulated_fields
return type(f"{model.__name__}AutoAdmin", (admin.ModelAdmin,), admin_attrs)
How to Use It in admin.py
Now in your admin.py
, import the generator and register your models like this:
from django.contrib import admin
from django.apps import apps
from .utils.auto_admin import generate_auto_admin # adjust path accordingly
app_models = apps.get_app_config('your_app_name').get_models()
for model in app_models:
try:
admin.site.register(model, generate_auto_admin(model))
except admin.sites.AlreadyRegistered:
pass
Just replace 'your_app_name'
with the name of your app. This loop will automatically register all models using their dynamic ModelAdmin classes.
Why This Works
In regular Python, class variables like list_display = list_display
won’t work if list_display
is defined outside the class. But using type()
like this:
type("MyAdmin", (admin.ModelAdmin,), {"list_display": [...], ...})
We bypass that issue by dynamically injecting attributes directly into the class definition at runtime.
This small utility has saved me hours of repetitive admin setup. And because it’s introspection-based, it scales beautifully across apps and teams — without sacrificing readability or maintainability.
Try it in your own project, and let me know how it goes.
Need more admin power tips? Check out this explore Search and tutorials to supercharge your app.