ModelAdmin API Reference¶
The ModelAdmin class encapsulates all admin options and functionality for a model. It serves as the central configuration point for how a model is displayed and interacted with in the admin interface.
Class Definition¶
from djadmin import ModelAdmin
class ModelAdmin(metaclass=ModelAdminMetaclass):
"""
Encapsulates all admin options and functionality for a model.
"""
Constructor¶
Parameters¶
- model (
type): The Django model class this admin is managing - admin_site (
AdminSite): The AdminSite instance this admin is registered to
Notes¶
- ModelAdmin instances are typically created automatically by
AdminSite.register()or the@registerdecorator - You rarely need to instantiate ModelAdmin directly
ListView Configuration¶
list_display¶
Specifies which fields/columns to display in the list view.
Type: List of strings, callables, or Column instances
Default: None (will be initialized to [Column('__str__')])
Examples:
# Simple field names (Django admin style)
class ProductAdmin(ModelAdmin):
list_display = ['name', 'sku', 'price']
# With callables
class ProductAdmin(ModelAdmin):
def formatted_price(self, obj):
return f"${obj.price:.2f}"
list_display = ['name', 'sku', formatted_price]
# Using Column for enhanced configuration
from djadmin import Column
class ProductAdmin(ModelAdmin):
list_display = [
Column('name'),
Column('sku', label='SKU Code', classes='font-mono'),
Column('price', empty_value='N/A'),
]
# Mixed style
class ProductAdmin(ModelAdmin):
list_display = [
'name',
Column('sku', label='SKU Code'),
'price',
]
See also: Column API Reference
general_actions¶
Actions available from the list view that don't require record selection.
Type: List of Action classes
Default: None (uses plugin-provided defaults: [ListAction, AddAction])
Examples:
from djadmin import ModelAdmin
from djadmin.actions import BaseAction, GeneralActionMixin
from djadmin.actions.view_mixins import TemplateViewActionMixin
class ImportAction(GeneralActionMixin, TemplateViewActionMixin, BaseAction):
label = 'Import'
icon = 'upload'
def get_template_name(self):
return 'myapp/import.html'
class ProductAdmin(ModelAdmin):
# Override default general_actions
general_actions = [ListAction, AddAction, ImportAction]
Default Actions (from core plugin):
- ListAction - Main list view
- AddAction - Create new record
See also: Actions API Reference
bulk_actions¶
Actions that operate on multiple selected records from checkboxes.
Type: List of Action classes
Default: None (uses plugin-provided defaults: [DeleteBulkAction])
Examples:
from djadmin import ModelAdmin
from djadmin.actions import BaseAction, BulkActionMixin
from djadmin.actions.view_mixins import FormViewActionMixin
from django import forms
class BulkStatusForm(forms.Form):
status = forms.ChoiceField(choices=[('active', 'Active'), ('inactive', 'Inactive')])
class BulkChangeStatusAction(BulkActionMixin, FormViewActionMixin, BaseAction):
label = 'Change Status'
form_class = BulkStatusForm
def get_template_name(self):
return 'myapp/bulk_status.html'
class ProductAdmin(ModelAdmin):
bulk_actions = [DeleteBulkAction, BulkChangeStatusAction]
Default Actions (from core plugin):
- DeleteBulkAction - Delete selected records
See also: Actions API Reference
record_actions¶
Actions that operate on a single record (displayed in list rows or detail pages).
Type: List of Action classes
Default: None (uses plugin-provided defaults: [EditAction, DeleteAction])
Examples:
from djadmin import ModelAdmin
from djadmin.actions import BaseAction, RecordActionMixin
from djadmin.actions.view_mixins import TemplateViewActionMixin
class DuplicateAction(RecordActionMixin, TemplateViewActionMixin, BaseAction):
label = 'Duplicate'
icon = 'copy'
def get_template_name(self):
return 'myapp/duplicate.html'
class ProductAdmin(ModelAdmin):
record_actions = [EditAction, DeleteAction, DuplicateAction]
Default Actions (from core plugin):
- EditAction - Edit record
- DeleteAction - Delete record
See also: Actions API Reference
paginate_by¶
Number of records to display per page in the list view.
Type: int
Default: 100
Example:
pagination_class¶
Custom pagination class for the list view.
Type: Django pagination class or None
Default: None (uses Django's default Paginator)
Example:
from django.core.paginator import Paginator
class CustomPaginator(Paginator):
def __init__(self, *args, **kwargs):
kwargs['orphans'] = 5 # Move last few items to previous page
super().__init__(*args, **kwargs)
class ProductAdmin(ModelAdmin):
pagination_class = CustomPaginator
Form Configuration¶
form_class¶
Base form class used for both create and update views (unless overridden by create_form_class or update_form_class).
Type: ModelForm class or None
Default: None (auto-generates form)
Example:
from django import forms
from myapp.models import Product
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = '__all__'
widgets = {
'description': forms.Textarea(attrs={'rows': 5}),
}
class ProductAdmin(ModelAdmin):
form_class = ProductForm # Used for both create and update
fields¶
Base field list for both create and update forms (unless overridden by create_fields or update_fields).
Type: List of field names or '__all__'
Default: '__all__'
Example:
class ProductAdmin(ModelAdmin):
fields = ['name', 'sku', 'price', 'description'] # Exclude 'created_at'
CreateView Configuration¶
create_form_class¶
Form class specifically for creating new records. Overrides form_class for create views.
Type: ModelForm class or None
Default: None (falls back to form_class)
Example:
class ProductCreateForm(forms.ModelForm):
# Special fields only needed during creation
send_notification = forms.BooleanField(required=False)
class Meta:
model = Product
fields = '__all__'
class ProductAdmin(ModelAdmin):
create_form_class = ProductCreateForm
form_class = ProductForm # Used for updates
create_fields¶
Field list specifically for creating new records. Overrides fields for create views.
Type: List of field names, '__all__', or None
Default: None (falls back to fields)
Example:
class ProductAdmin(ModelAdmin):
create_fields = ['name', 'sku', 'price'] # Limited fields for creation
update_fields = ['name', 'price', 'description', 'status'] # More fields for updates
create_view_class¶
Custom view class for create operations. Bypasses ViewFactory if provided.
Type: Django view class or None
Default: None (uses ViewFactory)
Example:
from django.views.generic import CreateView
class CustomProductCreateView(CreateView):
template_name = 'custom_create.html'
def form_valid(self, form):
# Custom creation logic
response = super().form_valid(form)
send_notification(form.instance)
return response
class ProductAdmin(ModelAdmin):
create_view_class = CustomProductCreateView
DetailView/UpdateView Configuration¶
update_form_class¶
Form class specifically for updating existing records. Overrides form_class for detail/update views.
Type: ModelForm class or None
Default: None (falls back to form_class)
Example:
class ProductUpdateForm(forms.ModelForm):
# Additional fields for updates
change_reason = forms.CharField(required=False)
class Meta:
model = Product
fields = '__all__'
class ProductAdmin(ModelAdmin):
update_form_class = ProductUpdateForm
update_fields¶
Field list specifically for updating existing records. Overrides fields for detail/update views.
Type: List of field names, '__all__', or None
Default: None (falls back to fields)
Example:
class ProductAdmin(ModelAdmin):
update_fields = ['name', 'price', 'description', 'status'] # Can't change SKU
create_fields = ['name', 'sku', 'price'] # SKU required at creation
detail_view_class¶
Custom view class for detail/update operations. Bypasses ViewFactory if provided.
Type: Django view class or None
Default: None (uses ViewFactory)
Example:
from django.views.generic import UpdateView
class CustomProductUpdateView(UpdateView):
template_name = 'custom_update.html'
def get_queryset(self):
# Custom queryset logic
return super().get_queryset().select_related('category')
class ProductAdmin(ModelAdmin):
detail_view_class = CustomProductUpdateView
ListView Override¶
list_view_class¶
Custom view class for list operations. Bypasses ViewFactory if provided.
Type: Django view class or None
Default: None (uses ViewFactory)
Example:
from django.views.generic import ListView
class CustomProductListView(ListView):
template_name = 'custom_list.html'
def get_queryset(self):
# Custom filtering
qs = super().get_queryset()
if not self.request.user.is_superuser:
qs = qs.filter(status='active')
return qs
class ProductAdmin(ModelAdmin):
list_view_class = CustomProductListView
Feature Indicators¶
Feature indicators are attributes that trigger plugin requirements. When set, they indicate that your ModelAdmin needs specific plugin features.
search_fields¶
Enables search functionality (requires 'search' feature from a plugin).
Type: List of field names or None
Default: None
Triggers: 'search' feature requirement
Example:
class ProductAdmin(ModelAdmin):
search_fields = ['name', 'sku', 'description']
# This requires a plugin that provides the 'search' feature
list_filter¶
Enables filtering sidebar (requires 'filter' feature from a plugin).
Type: List of field names or filter specifications, or None
Default: None
Triggers: 'filter' feature requirement
Example:
class ProductAdmin(ModelAdmin):
list_filter = ['status', 'category', 'created_at']
# This requires a plugin that provides the 'filter' feature
ordering¶
Default ordering for list view (requires 'ordering' feature from a plugin).
Type: List of field names (prefix with '-' for descending), or None
Default: None
Triggers: 'ordering' feature requirement
Example:
inlines¶
Inline model admin classes for related models (requires 'inlines' feature from a plugin).
Type: List of InlineModelAdmin classes or None
Default: None
Triggers: 'inlines' feature requirement
Example:
class OrderItemInline(InlineModelAdmin):
model = OrderItem
extra = 1
class OrderAdmin(ModelAdmin):
inlines = [OrderItemInline]
# This requires a plugin that provides the 'inlines' feature
inline_sortable¶
Enable drag-and-drop sorting for inlines (requires 'sortable' feature from a plugin).
Type: bool
Default: False
Triggers: 'sortable' feature requirement
Example:
class ProductAdmin(ModelAdmin):
inlines = [ImageInline]
inline_sortable = True # Enable drag-and-drop for images
Feature Advertising¶
FEATURE_INDICATORS¶
FEATURE_INDICATORS: ClassVar[dict[str, list[str]]] = {
'search': ['search_fields'],
'filter': ['list_filter'],
'ordering': ['ordering'],
'inlines': ['inlines'],
'sortable': ['inline_sortable'],
}
Class-level mapping of features to their indicator attributes.
Type: dict[str, list[str]]
Use: Internal - defines which attributes trigger which feature requirements
Custom Features:
You can extend FEATURE_INDICATORS to add custom feature detection:
class ProductAdmin(ModelAdmin):
FEATURE_INDICATORS = {
**ModelAdmin.FEATURE_INDICATORS,
'export': ['export_formats'], # Custom feature
}
export_formats = ['csv', 'xlsx'] # Triggers 'export' feature
requested_features¶
@property
def requested_features(self) -> set:
"""Get set of features requested by checking indicator attributes."""
Returns the set of features that this ModelAdmin requests based on which feature indicator attributes are set.
Returns: set[str] - Set of feature names
Example:
class ProductAdmin(ModelAdmin):
search_fields = ['name']
list_filter = ['category']
admin = ProductAdmin(Product, site)
print(admin.requested_features) # {'search', 'filter'}
Notes:
- Called automatically at Django startup for validation
- Raises ImproperlyConfigured if a requested feature isn't provided by any plugin
- Uses truthy check on attributes (empty lists don't trigger features)
Properties¶
opts¶
Convenient access to the model's _meta object.
Returns: django.db.models.options.Options
Example:
admin = ProductAdmin(Product, site)
print(admin.opts.verbose_name) # 'product'
print(admin.opts.app_label) # 'webshop'
list_url_name¶
Returns the URL name for the list view of this model.
Returns: str - URL name (e.g., 'webshop_product_list')
Example:
admin = ProductAdmin(Product, site)
print(admin.list_url_name) # 'webshop_product_list'
# Use with reverse:
from django.urls import reverse
url = reverse(f'djadmin:{admin.list_url_name}')
Form/Fields Resolution Logic¶
The ModelAdmin resolves which form and fields to use based on a fallback hierarchy:
For CreateView (AddAction):
create_form_class = self.create_form_class or self.form_class or auto_generated_form
create_fields = self.create_fields or self.fields or '__all__'
For DetailView/UpdateView (EditAction):
update_form_class = self.update_form_class or self.form_class or auto_generated_form
update_fields = self.update_fields or self.fields or '__all__'
Example:
class ProductAdmin(ModelAdmin):
# Base configuration (used if specific not set)
form_class = ProductForm
fields = '__all__'
# Create-specific (overrides base)
create_fields = ['name', 'sku', 'price']
# Update-specific (overrides base)
update_form_class = ProductUpdateForm
update_fields = ['name', 'price', 'description']
# Results:
# - Create: uses ProductForm with fields ['name', 'sku', 'price']
# - Update: uses ProductUpdateForm with fields ['name', 'price', 'description']
Usage Examples¶
Basic Registration¶
from djadmin import ModelAdmin, register
from myapp.models import Product
@register(Product)
class ProductAdmin(ModelAdmin):
list_display = ['name', 'sku', 'price']
paginate_by = 50
Advanced Configuration¶
from djadmin import ModelAdmin, register, Column
from djadmin.actions import BaseAction, GeneralActionMixin
from myapp.models import Product
class ExportAction(GeneralActionMixin, BaseAction):
label = 'Export'
# ... implementation
@register(Product)
class ProductAdmin(ModelAdmin):
# List view
list_display = [
Column('name'),
Column('sku', label='SKU Code', classes='font-mono'),
Column('price', empty_value='N/A'),
'status',
]
paginate_by = 25
# Actions
general_actions = [ListAction, AddAction, ExportAction]
bulk_actions = [DeleteBulkAction]
record_actions = [EditAction, DeleteAction]
# Forms
form_class = ProductForm
create_fields = ['name', 'sku', 'price', 'category']
update_fields = ['name', 'price', 'description', 'status', 'category']
Custom View Classes¶
from django.views.generic import ListView, CreateView
class CustomProductListView(ListView):
paginate_by = 10
def get_queryset(self):
qs = super().get_queryset()
return qs.filter(status='active').select_related('category')
class CustomProductCreateView(CreateView):
def form_valid(self, form):
response = super().form_valid(form)
notify_team(form.instance)
return response
@register(Product)
class ProductAdmin(ModelAdmin):
list_view_class = CustomProductListView
create_view_class = CustomProductCreateView
See Also¶
- AdminSite API Reference - Registering ModelAdmin
- Actions API Reference - Creating custom actions
- Column API Reference - Configuring list_display columns
- Mixins API Reference - View mixins for custom views