SpireModelAdmin
Purpose: Provide a zero-configuration Django admin interface for your models with intelligent defaults that automatically discover fields, filters, search capabilities, and display options.
Why SpireModelAdmin?
Django's admin interface requires manual configuration of list_display, list_filter, search_fields, and more for each model. SpireModelAdmin eliminates this boilerplate by analyzing your model's fields and automatically generating sensible defaults:
- Discovers searchable text fields (CharField, TextField)
- Identifies filterable fields (BooleanField, DateField, ForeignKey, choices)
- Generates appropriate list display columns
- Sets readonly fields for audit fields (
created_datetime,is_active,is_deleted) - Enables pagination and ordering out of the box
Quick Start
1. Import and Register
# myapp/admin.py
from django.contrib import admin
from django_spire.contrib.admin.admin import SpireModelAdmin
from myapp.models import Task
@admin.register(Task)
class TaskAdmin(SpireModelAdmin):
model_class = Task
That's it! The admin interface is now fully configured with intelligent defaults.
2. Access in Django Admin
Navigate to /admin/myapp/task/ and you'll see:
- All model fields displayed in the list view (up to 10 columns)
- Search boxes for text-based fields
- Filter sidebar for boolean, date, and foreign key fields
- Readonly display for audit fields
- 25 items per page with newest-first ordering
What Gets Configured Automatically
| Configuration | Auto-behavior | Max items |
|---|---|---|
| List Display | All non-relational fields except M2M | 10 columns |
| Search Fields | CharField and TextField fields | 5 fields |
| List Filter | BooleanField, DateField, ForeignKey, CharField with choices | Unlimited |
| Readonly Fields | created_datetime, is_active, is_deleted |
Auto-detected |
| Ordering | Newest first (-id) |
Single direction |
| Pagination | 25 items per page | Fixed |
Customization
You can override any auto-configured behavior by simply defining it in your admin class:
Custom List Display
@admin.register(Task)
class TaskAdmin(SpireModelAdmin):
model_class = Task
list_display = ('id', 'name', 'status', 'assigned_to')
When you define list_display, SpireModelAdmin respects your choice and doesn't auto-configure.
Custom Search Fields
@admin.register(Task)
class TaskAdmin(SpireModelAdmin):
model_class = Task
search_fields = ('name', 'description', 'assigned_to__username')
Custom Filters
@admin.register(Task)
class TaskAdmin(SpireModelAdmin):
model_class = Task
list_filter = ('status', 'created_datetime', 'assigned_to')
Custom Readonly Fields
@admin.register(Task)
class TaskAdmin(SpireModelAdmin):
model_class = Task
readonly_fields = ('created_datetime', 'id', 'slug')
Custom Ordering
@admin.register(Task)
class TaskAdmin(SpireModelAdmin):
model_class = Task
ordering = ('-created_datetime', 'name')
Custom Pagination
Configuration Limits
You can adjust the limits for auto-discovery to suit your models:
@admin.register(Task)
class TaskAdmin(SpireModelAdmin):
model_class = Task
# Maximum text fields to include in search
max_search_fields = 3
# Maximum columns to display in list view
max_list_display = 8
How It Works
SpireModelAdmin uses Python's __init_subclass__ hook to automatically configure your admin class when it's defined:
- Field Discovery: Analyzes all model fields using Django's
_metaAPI - Smart Exclusions: Skips M2M fields, reverse relations, and private fields
- Categorization: Groups fields by type (text, boolean, date, foreign key)
- Configuration: Populates list_display, search_fields, list_filter, etc.
- Trailing Fields: Audit fields (
is_active,is_deleted) always appear at the end
The configuration only runs once via _spire_configured flag to avoid redundant setup.
Common Patterns
Model with Foreign Keys
from django.contrib import admin
from django_spire.contrib.admin.admin import SpireModelAdmin
from myapp.models import Task, User
@admin.register(Task)
class TaskAdmin(SpireModelAdmin):
model_class = Task
With a model like:
class Task(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
assigned_to = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.CharField(choices=StatusChoices.choices)
created_datetime = models.DateTimeField(auto_now_add=True)
SpireModelAdmin automatically:
- Adds
nameanddescriptionto search - Adds
assigned_toandstatusto filters - Displays
name,description,assigned_to,status,created_datetime
Model with Activity Tracking
If your model uses HistoryModelMixin or ActivityMixin:
The audit fields (created_datetime, is_active, is_deleted) are automatically marked readonly and placed at the end of the list display.
Combining with Standard Django Admin
You can mix SpireModelAdmin's auto-configuration with traditional Django admin features:
@admin.register(Task)
class TaskAdmin(SpireModelAdmin):
model_class = Task
# Auto-configured
# - list_display, list_filter, search_fields
# Your custom additions
actions = ['mark_complete', 'mark_incomplete']
fieldsets = (
('Basic Info', {
'fields': ('name', 'description')
}),
('Assignment', {
'fields': ('assigned_to', 'status')
}),
('Metadata', {
'fields': ('created_datetime', 'is_active'),
'classes': ('collapse',)
}),
)
def mark_complete(self, request, queryset):
queryset.update(status=StatusChoices.COMPLETE)
mark_complete.short_description = "Mark as complete"
Note
Custom fieldsets will override the auto-configured layout. Use only the SpireModelAdmin defaults if you want the automatic field discovery.
Field Type Support
SpireModelAdmin recognizes these field types for auto-configuration:
| Field Type | Searchable? | Filterable? | Displayed? |
|---|---|---|---|
| CharField | ✓ | If has choices | ✓ |
| TextField | ✓ | ✗ | ✓ |
| IntegerField | ✗ | ✗ | ✓ |
| BooleanField | ✗ | ✓ | ✓ |
| DateField | ✗ | ✓ | ✓ |
| DateTimeField | ✗ | ✓ | ✓ |
| ForeignKey | ✗ | ✓ | ✓ |
| DecimalField | ✗ | ✗ | ✓ |
| EmailField | ✓ | ✗ | ✓ |
Fields starting with _ are skipped. ManyToMany and reverse relations are excluded.
Example: Complete Setup
Here's a real-world example from the test project:
# test_project/apps/model_and_service/admin.py
from django.contrib import admin
from django_spire.contrib.admin.admin import SpireModelAdmin
from test_project.apps.model_and_service.models import Adult, Kid
@admin.register(Adult)
class AdultAdmin(SpireModelAdmin):
model_class = Adult
@admin.register(Kid)
class KidAdmin(SpireModelAdmin):
model_class = Kid
With these models:
class Adult(ActivityMixin, HistoryModelMixin):
first_name = models.CharField(max_length=32)
last_name = models.CharField(max_length=32)
description = models.TextField()
personality_type = models.CharField(
max_length=3,
choices=[('int', 'Introvert'), ('ext', 'Extrovert')],
)
email = models.EmailField(blank=True, null=True)
favorite_number = models.IntegerField()
birth_date = models.DateField()
weight_lbs = models.DecimalField(max_digits=7, decimal_places=3)
best_friend = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True)
def __str__(self) -> str:
return f'{self.first_name} {self.last_name}'
The automatically configured AdultAdmin will have:
- Search:
first_name,last_name,description,email(4 out of 5 max) - Filters:
personality_type,birth_date,best_friend - Display:
first_name,last_name,description,personality_type,email,favorite_number,birth_date,weight_lbs,best_friend,is_active(10 columns) - Readonly:
created_datetime,is_active,is_deleted - Ordering: Newest first (
-id) - Pagination: 25 per page