The steps for enabling drag-and-drop sorting functionality is identical to Grappelli’s (even with the vanilla Django admin), so the Grappelli documentation for this feature is the best reference. This is equally true of sortables in Django Suit—do not follow Django Suit’s instructions for sortables, as they will not work. The other features of Grappelli have not been ported to work with vanilla Django, but in principle they should all still work with nested inlines using django-nested-admin if Grappelli is installed. If you run into any difficulty with this, please create an issue on this project’s Github.

If you want to have a sortable inline and also want to hide the field you’re sorting, you can use SortableHiddenMixin. Note that this mixin sets sortable_field_name to position by default (though this can be overridden by setting sortable_field_name on your inline class) and must be inherited prior to NestedStackedInline or NestedTabularInline.

import nested_admin
from django.contrib import admin
from .models import TableOfContents, TocArticle, TocSection

class TocArticleInline(nested_admin.SortableHiddenMixin,
    model = TocArticle

class TocSectionInline(nested_admin.SortableHiddenMixin,
    model = TocSection
    inlines = [TocArticleInline]

class TableOfContentsAdmin(nested_admin.NestedModelAdmin):
    inlines = [TocSectionInline]


Adding or removing an inline fires the formset:added and formset:removed events, respectively, that were added to Django in 1.9 (#15760). This is particularly useful for when you need to execute javascript upon an inline being added (for instance, to initialize a custom widget). The API is the same as Django 1.9, so reference the official Django docs for information about how to use these events. In addition, django-nested-admin also emits events for when the delete checkbox (or button, in Grappelli) is toggled with the formset:deleted and formset:undeleted events. Less likely to be used, but still available, are the following events:

Fired whenever the state of a formset changes
Fired after an inline has been initialized, either on load or after being added
Fired whenever a drag-and-drop operation or removal necessitates changing the name, id, and for attributes of the elements within a form or formset. Ideally custom Django widgets with javascript hooks should be written so that they do not need to be reinitialized if a form field’s id or name changes, but in cases where they do, use this event to refresh or reinitialize the bindings.