Skip to content

Hook Reference

Complete reference of all available hooks in django-admin-deux.

Source: djadmin/plugins/__init__.py

Feature Advertising

djadmin_provides_features()

Advertise features your plugin provides.

Returns: List[str] - Feature names

Example:

@hookimpl
def djadmin_provides_features():
    return ['search', 'export']

Usage: Features are validated at startup against ModelAdmin.FEATURE_INDICATORS.


Action Registration

djadmin_get_default_general_actions()

Provide default general actions (list-level actions, main entry points).

Returns: List[Type[BaseAction]] - Action classes

Example:

@hookimpl
def djadmin_get_default_general_actions():
    from .actions import ExportAction
    return [ExportAction]

Built-in: Core plugin provides ListAction and AddAction.

djadmin_get_default_bulk_actions()

Provide default bulk actions (operate on selected records).

Returns: List[Type[BaseAction]] - Action classes

Example:

@hookimpl
def djadmin_get_default_bulk_actions():
    from .actions import BulkUpdateAction
    return [BulkUpdateAction]

Built-in: Core plugin provides DeleteBulkAction.

djadmin_get_default_record_actions()

Provide default record actions (operate on single records).

Returns: List[Type[BaseAction]] - Action classes

Example:

@hookimpl
def djadmin_get_default_record_actions():
    from .actions import DuplicateAction
    return [DuplicateAction]

Built-in: Core plugin provides EditAction and DeleteAction.

djadmin_register_actions()

Register custom action classes with identifiers.

Returns: Dict[str, Type[BaseAction]] - Mapping of identifier to action class

Example:

@hookimpl
def djadmin_register_actions():
    return {
        'export_pdf': ExportPDFAction,
        'send_email': SendEmailAction,
    }

Usage: Allows referencing actions by string identifier in ModelAdmin configuration.


View Customization (Registry Pattern)

All view customization hooks use a registry pattern: they return dictionaries mapping action classes to values. The factory checks isinstance(action, key) for each key, allowing plugins to target specific action types or base classes.

djadmin_get_action_view_mixins(action)

Provide mixins for generated views.

Args: - action - Action instance (for context)

Returns: Dict[Type, List[Type]] - Mapping of action classes to mixin lists

Example:

@hookimpl
def djadmin_get_action_view_mixins(action):
    from djadmin.actions.view_mixins import ListActionMixin
    from .mixins import SearchMixin

    return {
        ListActionMixin: [SearchMixin],
    }

Built-in: Core plugin adds DjAdminViewMixin to all actions.

djadmin_get_action_view_base_class(action)

Override base view class for specific actions.

Args: - action - Action instance

Returns: Dict[Type, Type] - Mapping of action classes to base view classes

Example:

@hookimpl
def djadmin_get_action_view_base_class(action):
    return {
        CustomListAction: CustomListView,
    }

djadmin_get_action_view_assets(action)

Provide CSS/JS assets for views.

Args: - action - Action instance

Returns: Dict[Type, Dict[str, List[str | JSAsset | CSSAsset]]] - Mapping of action classes to asset dicts

Assets can be specified as plain strings or asset objects (JSAsset/CSSAsset) for advanced features like module loading, deferred loading, or render-blocking behavior.

Example:

@hookimpl
def djadmin_get_action_view_assets(action):
    from djadmin import JSAsset, CSSAsset
    from djadmin.actions.base import BaseAction

    return {
        BaseAction: {
            'css': ['myfeature/css/theme.css'],
            'js': [
                # Critical web component JS - loads before rendering to prevent layout shift
                JSAsset(src='myfeature/js/webcomponents.js', module=True, blocking=True),
                # Non-critical enhancement - deferred loading
                JSAsset(src='myfeature/js/feature.js', defer=True),
            ],
        }
    }

Script Loading Strategies:

  • blocking=True: Loads in <head> before page renders. Use for critical scripts that must execute before rendering. Trade-off: delays initial render. Note: Does NOT work with module=True - ES modules are always deferred by browser specification.

  • defer=True: Loads after DOM parsing but before DOMContentLoaded. Best for most application JavaScript that enhances existing elements.

  • async_=True: Loads asynchronously without blocking. Use for completely independent scripts like analytics.

  • module=True: ES module script (type="module"). Always deferred by browser spec - cannot be made render-blocking even with blocking=True.

Built-in: Theme plugin provides default CSS/JS for all actions.

djadmin_get_action_view_attributes(action)

Add attributes to generated view classes.

Args: - action - Action instance (access to model, model_admin, admin_site)

Returns: Dict[Type, Dict[str, Any]] - Mapping of action classes to attribute dicts

Example:

@hookimpl
def djadmin_get_action_view_attributes(action):
    from djadmin.actions.view_mixins import ListActionMixin

    return {
        ListActionMixin: {
            'paginate_by': action.model_admin.paginate_by,
        }
    }

Built-in: Core plugin provides pagination configuration.

djadmin_get_action_view_attribute_bindings(action)

Specify which action attributes should be bound to the view.

Args: - action - Action instance

Returns: Dict[Type, List[str]] - Mapping of action classes to attribute name lists

Example:

@hookimpl
def djadmin_get_action_view_attribute_bindings(action):
    from djadmin.actions.base import BaseAction

    return {
        BaseAction: ['get_template_names'],
    }

Built-in: Core plugin binds methods like get_queryset, get_form_class, etc.


UI Extension Hooks

Added in: Milestone 2

These hooks allow plugins to extend the user interface with custom widgets and icons.

djadmin_get_sidebar_widgets(action)

Provide sidebar widgets for action views.

Args: - action - Action instance (for context)

Returns: Dict[Type, List[SidebarWidget]] - Mapping of action classes to widget lists

Example:

@hookimpl
def djadmin_get_sidebar_widgets(action):
    from djadmin.dataclasses import SidebarWidget
    from djadmin.actions.list_view import ListAction

    def get_help_context(view):
        return {
            'model_name': view.model._meta.verbose_name,
            'help_text': view.model_admin.help_text,
        }

    def has_help_text(view):
        return hasattr(view.model_admin, 'help_text')

    return {
        ListAction: [
            SidebarWidget(
                template='myapp/help_widget.html',
                context_callback=get_help_context,
                condition=has_help_text,
                order=200,  # Display after filters
                identifier='help_widget',
            )
        ]
    }

SidebarWidget Attributes: - template (str, required) - Path to widget template - context_callback (Callable[[view], dict], optional) - Dynamic context provider - order (int, default: 100) - Display order (lower = first) - condition (Callable[[view], bool], optional) - Display condition - identifier (str, optional) - Unique ID for debugging

Built-in: Core plugin provides search widget (order=0).

See also: Sidebar Widgets Guide

djadmin_get_column_header_icons(action)

Provide icons for table column headers.

Args: - action - Action instance (for context)

Returns: Dict[Type, List[ColumnHeaderIcon]] - Mapping of action classes to icon lists

Example:

@hookimpl
def djadmin_get_column_header_icons(action):
    from djadmin.dataclasses import ColumnHeaderIcon
    from djadmin.actions.list_view import ListAction

    def get_icon_template(view, column_name):
        # Dynamic icon based on state
        if view.is_column_active(column_name):
            return 'myapp/icons/active.html'
        return 'myapp/icons/inactive.html'

    def get_icon_url(view, column_name):
        # Generate URL for icon action
        return f'{view.request.path}?toggle={column_name}'

    def get_icon_title(view, column_name):
        return f'Toggle {column_name}'

    def should_display(view, column_name):
        # Only show for certain columns
        return column_name in ['status', 'featured']

    return {
        ListAction: [
            ColumnHeaderIcon(
                icon_template=get_icon_template,
                url=get_icon_url,
                title=get_icon_title,
                condition=should_display,
                order=50,
                identifier='toggle_icon',
            )
        ]
    }

ColumnHeaderIcon Attributes: - icon_template (Callable[[view, column_name], str], required) - Icon template path - url (Callable[[view, column_name], str], required) - Icon URL - title (Callable[[view, column_name], str], required) - Tooltip text - css_class (str, default: '') - CSS classes for icon - order (int, default: 100) - Display order - condition (Callable[[view, column_name], bool], optional) - Display condition - identifier (str, optional) - Unique ID

Built-in: djadmin-filters plugin provides sort icons for orderable columns.

See also: Column Header Icons Guide



Query and Context Hooks

djadmin_modify_queryset(queryset, request, view)

Modify queryset before rendering.

Args: - queryset - Original queryset - request - HTTP request - view - View instance

Returns: QuerySet - Modified queryset

Example:

@hookimpl
def djadmin_modify_queryset(queryset, request, view):
    # Add search filtering
    if 'q' in request.GET:
        search_term = request.GET['q']
        return queryset.filter(title__icontains=search_term)
    return queryset

djadmin_add_context_data(context, request, view)

Add extra context data to views.

Args: - context - Current context dict - request - HTTP request - view - View instance

Returns: Dict[str, Any] - Additional context data

Example:

@hookimpl
def djadmin_add_context_data(context, request, view):
    return {
        'feature_enabled': True,
        'user_preferences': get_user_prefs(request.user),
    }

Built-in: Core plugin adds pagination helpers (page_range, show_first, show_last).


Hook Execution Order

Hooks are executed in plugin registration order. The core plugin is always first, followed by other plugins in INSTALLED_APPS order.

For hooks that collect values (like djadmin_get_default_general_actions), all plugin results are aggregated.

Complete Example

Here's a plugin using multiple hooks:

# myfeature/djadmin_hooks.py
from djadmin.plugins import hookimpl

@hookimpl
def djadmin_provides_features():
    return ['search']

@hookimpl
def djadmin_get_action_view_mixins(action):
    from djadmin.actions.view_mixins import ListActionMixin
    from .mixins import SearchMixin
    return {ListActionMixin: [SearchMixin]}

@hookimpl
def djadmin_get_action_view_assets(action):
    from djadmin import JSAsset
    from djadmin.actions.view_mixins import ListActionMixin
    return {
        ListActionMixin: {
            'css': ['myfeature/search.css'],
            'js': [JSAsset(src='myfeature/search.js', defer=True)],
        }
    }

@hookimpl
def djadmin_modify_queryset(queryset, request, view):
    if 'q' in request.GET:
        return queryset.filter(title__icontains=request.GET['q'])
    return queryset

@hookimpl
def djadmin_add_context_data(context, request, view):
    return {'search_term': request.GET.get('q', '')}

See Also