Migrating from ModelAdmin to Snippets

To provide a single, unified way to manage non-page Django models, the modeladmin contrib module has been deprecated in favor of the snippets module. This page explains how to migrate from modeladmin to snippets.

New in version 5.2: If you would rather not register the models as snippets, you can also use ModelViewSet. The migration explained with SnippetViewSet and SnippetViewSetGroup on this page can be substituted with ModelViewSet and ModelViewSetGroup. However, as of this release, the ModelViewSet does not support the following:

See Generic views for more details on using ModelViewSet.

Installation

Ensure wagtail.snippets is in your INSTALLED_APPS:

INSTALLED_APPS = [
    ...,
    'wagtail.snippets',
    ...,
]

Convert ModelAdmin class to SnippetViewSet

The SnippetViewSet class is the snippets-equivalent to the ModelAdmin class. To migrate a ModelAdmin class to a SnippetViewSet class, follow these instructions.

Change any imports of ModelAdmin and modeladmin_register to SnippetViewSet and register_snippet, respectively:

- from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register
+ from wagtail.snippets.models import register_snippet
+ from wagtail.snippets.views.snippets import SnippetViewSet

Change any references to ModelAdmin and modeladmin_register to SnippetViewSet and register_snippet, respectively:

- class MyModelAdmin(ModelAdmin):
+ class MySnippetViewSet(SnippetViewSet):
      ...

- modeladmin_register(MyModelAdmin)
+ register_snippet(MySnippetViewSet)

There are a few attributes of ModelAdmin that need to be renamed/adjusted for SnippetViewSet. The following is a table of such attributes and the changes that need to be made:

ModelAdmin attribute

SnippetViewSet attribute

Notes

add_to_admin_menu

add_to_admin_menu

Same attribute name, but the value defaults to False instead of True. Set to True to add a top-level menu item for the model.

menu_icon

icon

Same value, but different attribute name, as the icon is used throughout the admin and not just in the menu.

list_display

list_display

Same attribute name, but the list/tuple of strings must refer to existing attributes or methods on the model, not the SnippetViewSet class. If you have specified a string that refers to an attribute or method on the ModelAdmin class, you need to move it to the model. In addition, list_display now also supports instances of the wagtail.admin.ui.tables.Column component class.

list_filter

list_filter

Same attribute name and value, but filtering is built on top of the django-filter package under the hood, which behaves differently to ModelAdmin’s filters. See documentation for SnippetViewSet.list_filter and filterset_class for more details.

form_fields_exclude

exclude_form_fields

Same value, but different attribute name to better align with ModelViewSet.

-

template_prefix

New attribute. Set to the name of a template directory to override the "wagtailsnippets/snippets/" default. If set to "modeladmin/", the template directory structure will be equal to what ModelAdmin uses. Make sure any custom templates are placed in the correct directory according to this prefix. See Templates for more details.

Boolean properties in list_display

In ModelAdmin, boolean fields in list_display are rendered as tick/cross icons. To achieve the same behavior in SnippetViewSet, you need to use a wagtail.admin.ui.tables.BooleanColumn instance in SnippetViewSet.list_display:

from wagtail.admin.ui.tables import BooleanColumn


class MySnippetViewSet(SnippetViewSet):
    list_display = ("title", BooleanColumn("is_active"))

The BooleanColumn class works with both model fields and custom properties that return booleans.

New in version 5.1.1: The BooleanColumn class was added.

Convert ModelAdminGroup class to SnippetViewSetGroup

The SnippetViewSetGroup class is the snippets-equivalent to the ModelAdminGroup class. To migrate a ModelAdminGroup class to a SnippetViewSetGroup class, follow these instructions.

Change any imports of ModelAdminGroup to SnippetViewSetGroup:

- from wagtail.contrib.modeladmin.options import ModelAdminGroup
+ from wagtail.snippets.views.snippets import SnippetViewSetGroup

Change any references to ModelAdminGroup to SnippetViewSetGroup:

- class MyModelAdminGroup(ModelAdminGroup):
+ class MySnippetViewSetGroup(SnippetViewSetGroup):
      ...

- modeladmin_register(MyModelAdminGroup)
+ register_snippet(MySnippetViewSetGroup)

Unsupported features and customizations

Some features and customizations in ModelAdmin are not directly supported via SnippetViewSet, but may be achievable via other means that are more in line with Wagtail’s architecture.

Using ModelAdmin to manage Page models

ModelAdmin allows the registration of Page models, but the main use case is to create custom page listing views. The create and edit views are not supported by ModelAdmin, as there are page-specific operations in those views that are best handled by Wagtail’s page views. For this reason, registering a Page model as a snippet is not supported.

Note

In a future release, Wagtail will introduce a new “treeless” listing view for pages, as outlined in RFC 082: Treeless page listings and the Universal Listings discussion. This feature will allow for custom page listing views and will be the recommended way to achieve this use case. Feedback to this upcoming feature is welcome.

Customization of index view table rows and columns

ModelAdmin has a number of APIs that allow customization of the index view table rows and columns. Meanwhile, Wagtail has an internal generic tables UI framework that is used throughout the admin, including snippets. This table framework will become the standard way to build table elements in index views within the admin. As a result, the following APIs are not supported in snippets:

  • ModelAdmin.get_extra_attrs_for_row

    This can be achieved by creating a custom wagtail.admin.ui.tables.Table subclass and using it as the IndexView.table_class.

  • ModelAdmin.get_extra_class_names_for_field_col

    This can be achieved using a custom wagtail.admin.ui.tables.Column instance in SnippetViewSet.list_display.

  • ModelAdmin.list_display_add_buttons

    By default, the first column specified in list_display is the one that contains the buttons. Using custom wagtail.admin.ui.tables.Column instances in SnippetViewSet.list_display allows you to specify a different column.

  • Attributes for wagtail.contrib.modeladmin.mixins.ThumbnailMixin

    This mixin is used to show a thumbnail in the index view. A similar functionality can be achieved using a custom wagtail.admin.ui.tables.Column instance in SnippetViewSet.list_display. Hence, the following attributes are not supported:

    • ModelAdmin.thumb_image_field_name

    • ModelAdmin.thumb_image_width

    • ModelAdmin.thumb_classname

    • ModelAdmin.thumb_col_header_text

    • ModelAdmin.thumb_default

Custom CSS and JS

ModelAdmin supports inserting custom extra CSS and JS files into the admin via the following attributes on the ModelAdmin class:

  • ModelAdmin.index_view_extra_css

  • ModelAdmin.index_view_extra_js

  • ModelAdmin.form_view_extra_css

  • ModelAdmin.form_view_extra_js

  • ModelAdmin.inspect_view_extra_css

  • ModelAdmin.inspect_view_extra_js

This is not supported in snippets, but custom CSS and JS files can be inserted by overriding the respective view’s template. Alternatively, the insert_global_admin_css and insert_global_admin_js hooks can also be used.

Helper classes

Helper classes encapsulate the logic that is commonly used across views in ModelAdmin. These classes do not exist for snippets, as the similar logic now relies on generic patterns used across Wagtail.

  • ModelAdmin.url_helper_class

    The base ViewSet class has get_urlpatterns() and get_url_name() methods that can be used to manage the URLs of snippets views. The URL names can be used with Django’s reverse() function to generate URLs.

  • ModelAdmin.permission_helper_class

    Wagtail uses an internal permission policy system to manage permissions across the admin. The SnippetViewSet class has a permission_policy attribute, which is an instance of a permission policy class.

  • ModelAdmin.button_helper_class

    The pre-existing register_snippet_listing_buttons and construct_snippet_listing_buttons hooks can be used to customize the buttons in the listing view. For other views, custom buttons can be added by overriding the respective view’s template.

  • ModelAdmin.search_handler_class

    When searching snippets, Wagtail’s default search backend is used. To use a different backend, the search_backend_name attribute can be overridden. If the attribute is set to None, the search uses the Django ORM instead.

    As the search_handler_class attribute is not supported in snippets, the ModelAdmin.extra_search_kwargs attribute is also not supported.

Other customizations

  • ModelAdmin.empty_value_display and ModelAdmin.get_empty_value_display()

    This can be replaced by the Django-standard get_FOO_display() method on the model.

  • ModelAdmin.get_ordering(request)

    The SnippetViewSet.ordering attribute is responsible for the default ordering of the index view, before falling back to the model’s ordering. The index view handles per-request ordering based on the columns that are specified in list_display. For more advanced customization, you can override the index_view_class.

  • ModelAdmin.prepopulated_fields

    This is not supported in favor of TitleFieldPanel.

Keep ModelAdmin usage

If you still rely on ModelAdmin, it is still available as a separate wagtail-modeladmin package. The package is in maintenance mode and will not receive new features. If you have a use case that is not supported by SnippetViewSet and not described above, consider opening a feature request in the Wagtail issue tracker. For more details, see Issue tracking.