One of the most powerful features of Django's admin interface is its ability to update model objects directly through a secure and user-friendly dashboard. With just a few lines of code, you can customize how objects are updated, validate changes, make fields read-only, or even trigger automated actions.
This article covers:
-
How to update objects in Django Admin
-
Customizing object update forms
-
Using
readonly_fields
,save_model()
, andprepopulated_fields
-
Bulk updates with actions
-
Tips and common pitfalls
Updating Objects in Django Admin
By default, once a model is registered in the admin, you can click on any instance to update it. Django automatically generates a form from your model fields.
Basic Example
# blog/models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
# blog/admin.py
from django.contrib import admin
from .models import Post
admin.site.register(Post)
After registering the model, go to /admin/
, click on a Post
object, and edit it.
Customizing Object Update Forms
Use fields
to Control Editable Fields
class PostAdmin(admin.ModelAdmin):
fields = ('title', 'content', 'published')
This shows only the listed fields on the edit form.
Use readonly_fields
for Non-editable Display
class PostAdmin(admin.ModelAdmin):
readonly_fields = ('created_at', 'updated_at')
This displays those fields but makes them read-only.
Use fieldsets
for Structured Layout
class PostAdmin(admin.ModelAdmin):
fieldsets = (
('Post Content', {'fields': ('title', 'content')}),
('Status', {'fields': ('published',)}),
('Timestamps', {'fields': ('created_at', 'updated_at')}),
)
readonly_fields = ('created_at', 'updated_at')
Validating & Saving Data: save_model()
You can override the save_model
method in your custom admin class to handle special logic during updates.
class PostAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
if change:
print(f"Post '{obj.title}' is being updated.")
else:
print(f"New post '{obj.title}' is being created.")
super().save_model(request, obj, form, change)
✅ Add Prepopulated Fields
Useful when you want fields like slug
to auto-fill based on the title:
class PostAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('title',)}
Bulk Update Objects Using Admin Actions
You can define custom actions to update multiple objects at once.
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'published')
actions = ['publish_selected']
def publish_selected(self, request, queryset):
updated = queryset.update(published=True)
self.message_user(request, f"{updated} post(s) marked as published.")
publish_selected.short_description = "Mark selected posts as published"
✅ Now, select multiple posts from the list view and apply the "Mark selected posts as published" action.
Complete Example
models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
content = models.TextField()
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
admin.py
from django.contrib import admin
from .models import Post
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'published', 'updated_at')
fields = ('title', 'slug', 'content', 'published', 'created_at', 'updated_at')
readonly_fields = ('created_at', 'updated_at')
prepopulated_fields = {'slug': ('title',)}
actions = ['publish_selected']
def publish_selected(self, request, queryset):
count = queryset.update(published=True)
self.message_user(request, f"{count} post(s) published.")
publish_selected.short_description = "Publish selected posts"
def save_model(self, request, obj, form, change):
if change:
print(f"Post updated: {obj}")
else:
print(f"New post created: {obj}")
super().save_model(request, obj, form, change)
admin.site.register(Post, PostAdmin)
Tips
-
Use
formfield_overrides
to apply widgets (e.g., Markdown editor or rich text). -
Combine
readonly_fields
withfields
to prevent edits on system-generated fields. -
Use the
save_model()
hook to automatically log, audit, or transform data. -
Define custom
form
classes if you need validation or widget customization.
⚠️ Common Pitfalls
Pitfall | Solution |
---|---|
Can't edit a field | Check if it's in readonly_fields or missing from fields . |
Object not updating | Confirm that save_model() is calling super() properly. |
Read-only fields not updating in database | They must be auto-updated in the model (auto_now , etc.). |
Bulk actions don't run custom logic | Use queryset.update() wisely; it bypasses model save() . |
Conclusion
The Django Admin interface makes object updates extremely simple while still offering powerful customization. From manually editing individual objects to applying bulk updates and validations, the admin is a must-know tool for any Django developer.
By mastering field customization, save_model
, and admin actions, you can create an admin interface that’s efficient, user-friendly, and aligned with your project needs.