Today, let's have a look at how we can customize the admin panels in a Wagtail site.

Let's define a simple model first:

blog/models.py

class BlogPost(Page):
    body = MarkdownField(blank=True)
    tags = ClusterTaggableManager(through=BlogPostTag, blank=True)
    date = DateTimeField(blank=True, default=None, null=True, db_index=True)

To make the fields appear in the admin interface, they need to be added to one of the panels.

By default, a page has 3 different panels defined:

  • content_panels: everything shown under the tab "content" of a page
  • promote_panels: everything shown under the tab "promote" of a page
  • settings_panels: everything shown under the tab "settings" of a page

So, if we want to add the fields, we can add (append) them to the default one:

blog/models.py

class BlogPost(Page):
    body = MarkdownField(blank=True)
    tags = ClusterTaggableManager(through=BlogPostTag, blank=True)
    date = DateTimeField(blank=True, default=None, null=True, db_index=True)

    content_panels = Page.content_panels + [
        MultiFieldPanel(
            [
                FieldPanel('title', classname="full title"),
                FieldPanel('tags'),
            ],
            heading="Post Details",
        ),
        StreamFieldPanel('body'),
    ]

Let's say you want to completely replace the panel, you can just change it's definition:

blog/models.py

class BlogPost(Page):
    body = MarkdownField(blank=True)
    tags = ClusterTaggableManager(through=BlogPostTag, blank=True)
    date = DateTimeField(blank=True, default=None, null=True, db_index=True)

    content_panels = [
        MultiFieldPanel(
            [
                FieldPanel('title', classname="full title"),
                FieldPanel('tags'),
            ],
            heading="Post Details",
        ),
        StreamFieldPanel('body'),
    ]

We can make a MultiFieldPanel collapsible by adding the class name collapsible which I did with the post details:

blog/models.py

class BlogPost(Page):
    body = MarkdownField(blank=True)
    tags = ClusterTaggableManager(through=BlogPostTag, blank=True)
    date = DateTimeField(blank=True, default=None, null=True, db_index=True)

    content_panels = [
        MultiFieldPanel(
            [
                FieldPanel('title', classname="full title"),
                FieldPanel('tags'),
            ],
            heading="Post Details",
            classname="collapsible"
        ),
        StreamFieldPanel('body'),
    ]

You can also make the panel collapsed by default by adding the class name collapsed.

For a field panel, I also added the classes full and title to the FieldPanel. The class name full makes the field cover the complete width of the editor. The title class name gives the field a larger title size making it clear it's a title.

If you want to hide for example the settings, you can just set the variable settings_panel to an empty list:

blog/models.py

class BlogPost(Page):
    body = MarkdownField(blank=True)
    tags = ClusterTaggableManager(through=BlogPostTag, blank=True)
    date = DateTimeField(blank=True, default=None, null=True, db_index=True)

    content_panels = [
        MultiFieldPanel(
            [
                FieldPanel('title', classname="full title"),
                FieldPanel('tags'),
            ],
            heading="Post Details",
            classname="collapsible"
        ),
        StreamFieldPanel('body'),
    ]
    settings_pnels = []

You can find much more info about panels in the documentation.