CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-wagtail

A Django content management system with a user-friendly interface and powerful features for building websites and applications.

Overview
Eval results
Files

admin-interface.mddocs/

Admin Interface and Panels

Customizable admin interface with panel system for organizing edit forms, menu configuration, and extensible admin UI components. Wagtail's admin interface provides a user-friendly content management experience with powerful customization capabilities.

Capabilities

Panel System

Panel classes for organizing edit forms and controlling the admin interface layout.

class Panel:
    """
    Base panel class for edit forms.
    
    All panel types inherit from this base class.
    """
    def __init__(self, heading='', classname='', help_text='', **kwargs):
        """
        Initialize panel with display options.
        
        Parameters:
            heading (str): Panel heading text
            classname (str): CSS class for styling
            help_text (str): Help text displayed to users
        """

class FieldPanel(Panel):
    """
    Panel for editing a single model field.
    
    The most commonly used panel type for basic field editing.
    """
    def __init__(self, field_name, widget=None, heading='', classname='', help_text='', **kwargs):
        """
        Initialize field panel.
        
        Parameters:
            field_name (str): Name of the model field to edit
            widget (Widget): Custom form widget to use
            heading (str): Custom heading for the field
            classname (str): CSS class for styling
            help_text (str): Help text for the field
        """

class MultiFieldPanel(Panel):
    """
    Panel that groups multiple fields together under a common heading.
    """
    def __init__(self, children, heading='', classname='', help_text='', **kwargs):
        """
        Initialize multi-field panel.
        
        Parameters:
            children (list): List of child panels to group
            heading (str): Heading for the group
            classname (str): CSS class for styling
            help_text (str): Help text for the group
        """

class TitleFieldPanel(FieldPanel):
    """
    Special panel for title fields that enables automatic slug generation.
    """
    def __init__(self, field_name, **kwargs):
        """Initialize title field panel with slug generation."""

class PublishingPanel(Panel):
    """
    Panel that displays publishing workflow controls and status.
    """
    def __init__(self, **kwargs):
        """Initialize publishing panel."""

class CommentPanel(Panel):
    """
    Panel that displays the comments interface for collaborative editing.
    """
    def __init__(self, **kwargs):
        """Initialize comment panel."""

class InlinePanel(Panel):
    """
    Panel for editing related objects inline within the parent object's form.
    """
    def __init__(self, relation_name, panels=None, heading='', label='', min_num=None, max_num=None, classname='', help_text='', **kwargs):
        """
        Initialize inline panel.
        
        Parameters:
            relation_name (str): Name of the foreign key relation
            panels (list): List of panels for editing related objects
            heading (str): Panel heading
            label (str): Label for individual items
            min_num (int): Minimum number of items required
            max_num (int): Maximum number of items allowed
            classname (str): CSS class for styling
            help_text (str): Help text for the panel
        """

class ObjectList(Panel):
    """
    Container for organizing multiple panels into logical groups.
    """
    def __init__(self, children, heading='', classname='', **kwargs):
        """
        Initialize object list.
        
        Parameters:
            children (list): List of child panels
            heading (str): Group heading
            classname (str): CSS class for styling
        """

class TabbedInterface(Panel):
    """
    Creates a tabbed interface with multiple panel groups.
    """
    def __init__(self, children, **kwargs):
        """
        Initialize tabbed interface.
        
        Parameters:
            children (list): List of ObjectList panels for each tab
        """

Menu System

Classes for customizing the admin navigation menu.

class MenuItem:
    """
    Individual menu item in the admin interface.
    """
    def __init__(self, label, url, name=None, icon_name=None, attrs=None, order=1000, **kwargs):
        """
        Initialize menu item.
        
        Parameters:
            label (str): Display text for the menu item
            url (str): URL the menu item links to
            name (str): Unique identifier for the menu item
            icon_name (str): Icon to display with the menu item
            attrs (dict): Additional HTML attributes
            order (int): Sort order for menu positioning
        """

class Menu:
    """
    Container for organizing menu items.
    """
    def __init__(self, register_hook_name=None, construct_hook_name=None):
        """Initialize menu container."""
    
    def register_menu_item(self, menu_item):
        """Register a menu item with this menu."""

class SubmenuMenuItem(MenuItem):
    """
    Menu item that contains nested menu items.
    """
    def __init__(self, label, menu, **kwargs):
        """
        Initialize submenu item.
        
        Parameters:
            label (str): Display text for the submenu
            menu (Menu): Menu object containing child items
        """

ViewSets

ViewSet classes for creating complete admin interfaces for models.

class ViewSet:
    """
    Base viewset class providing a collection of views for a specific functionality.
    """
    name: str
    url_prefix: str
    
    def get_urlpatterns(self):
        """Get URL patterns for this viewset."""
    
    def get_admin_menu_item(self):
        """Get menu item for admin navigation."""

class ModelViewSet(ViewSet):
    """
    Complete CRUD interface for Django models.
    
    Provides list, create, edit, delete, and inspect views.
    """
    model: Model
    form_class: ModelForm
    index_template_name: str
    create_template_name: str
    edit_template_name: str
    delete_template_name: str
    
    def __init__(self, name, model=None, **kwargs):
        """
        Initialize model viewset.
        
        Parameters:
            name (str): Unique name for the viewset
            model (Model): Django model to manage
        """
    
    def get_queryset(self, request):
        """Get the queryset for listing objects."""
    
    def get_form_class(self, for_update=False):
        """Get the form class for creating/editing objects."""
    
    def get_edit_handler(self):
        """Get the edit handler (panel configuration) for forms."""

class PageViewSet(ModelViewSet):
    """
    Specialized viewset for page models with additional page-specific functionality.
    """
    template_name: str
    
    def get_edit_handler(self):
        """Get edit handler with page-specific panels."""

Admin Forms and Widgets

Form classes and widgets for the admin interface.

class WagtailAdminModelForm(forms.ModelForm):
    """
    Base form class for Wagtail admin forms.
    
    Provides consistent styling and functionality.
    """
    def __init__(self, *args, **kwargs):
        """Initialize admin form with Wagtail styling."""

class WagtailAdminPageForm(WagtailAdminModelForm):
    """
    Form class specifically for page editing with additional page functionality.
    """
    def clean(self):
        """Validate page-specific constraints."""

# Widget classes for form fields
class AdminAutoHeightTextInput(forms.Textarea):
    """Text input that automatically adjusts height."""

class AdminPageChooser(forms.Select):
    """Widget for choosing pages with search interface."""

class AdminImageChooser(forms.ClearableFileInput):
    """Widget for choosing images with preview."""

class AdminDocumentChooser(forms.ClearableFileInput):
    """Widget for choosing documents with metadata."""

class AdminTagWidget(forms.TextInput):
    """Widget for tag input with autocomplete."""

class AdminDateInput(forms.DateInput):
    """Date input widget with calendar picker."""

class AdminTimeInput(forms.TimeInput):
    """Time input widget with time picker."""

class AdminDateTimeInput(forms.DateTimeInput):
    """DateTime input widget with combined picker."""

Permission System

Classes for managing admin permissions and access control.

class PermissionHelper:
    """
    Helper class for checking permissions in admin views.
    """
    def __init__(self, model, inspect_view_enabled=False):
        """
        Initialize permission helper.
        
        Parameters:
            model (Model): Model to check permissions for
            inspect_view_enabled (bool): Whether inspect view is available
        """
    
    def user_can_list(self, user):
        """Check if user can view the listing page."""
    
    def user_can_create(self, user):
        """Check if user can create new objects."""
    
    def user_can_inspect_obj(self, user, obj):
        """Check if user can inspect a specific object."""
    
    def user_can_edit_obj(self, user, obj):
        """Check if user can edit a specific object."""
    
    def user_can_delete_obj(self, user, obj):
        """Check if user can delete a specific object."""

class PagePermissionHelper(PermissionHelper):
    """
    Permission helper specifically for page models with page-specific permissions.
    """
    def user_can_edit_obj(self, user, obj):
        """Check page-specific edit permissions."""

Usage Examples

Customizing Page Edit Interface

from wagtail.models import Page
from wagtail.fields import RichTextField, StreamField
from wagtail.admin.panels import (
    FieldPanel, MultiFieldPanel, InlinePanel, TabbedInterface, ObjectList
)
from django.db import models

class BlogPage(Page):
    """Blog page with custom admin interface."""
    date = models.DateField("Post date")
    intro = models.CharField(max_length=250)
    body = RichTextField(blank=True)
    featured_image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    
    # Organize fields into logical groups
    content_panels = Page.content_panels + [
        MultiFieldPanel([
            FieldPanel('date'),
            FieldPanel('intro'),
        ], heading="Article Information"),
        FieldPanel('body'),
        FieldPanel('featured_image'),
    ]
    
    # Create tabbed interface
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        ObjectList(Page.promote_panels, heading='Promote'),
        ObjectList(Page.settings_panels, heading='Settings'),
    ])

Creating Custom Admin Views

from wagtail.admin.viewsets import ModelViewSet
from wagtail.admin.ui.tables import Column, DateColumn
from django.db import models

class EventPage(Page):
    """Event page model."""
    event_date = models.DateField()
    location = models.CharField(max_length=255)
    capacity = models.IntegerField()

class EventPageViewSet(ModelViewSet):
    """Custom admin interface for events."""
    model = EventPage
    icon = 'date'
    menu_label = 'Events'
    menu_order = 200
    add_to_settings_menu = False
    
    # Customize the listing page
    list_display = ['title', 'event_date', 'location', 'capacity', 'live']
    list_filter = ['event_date', 'live']
    search_fields = ['title', 'location']
    
    # Custom columns for the listing
    def get_columns(self):
        return [
            Column('title', label='Event Title', sort_key='title'),
            DateColumn('event_date', label='Date', sort_key='event_date'),
            Column('location', label='Location'),
            Column('capacity', label='Capacity'),
        ]

# Register the viewset
event_viewset = EventPageViewSet('events')

Adding Custom Menu Items

from wagtail import hooks
from wagtail.admin.menu import MenuItem, Menu, SubmenuMenuItem
from django.urls import reverse, path
from django.http import HttpResponse

@hooks.register('register_admin_urls')
def register_admin_urls():
    """Register custom admin URLs."""
    return [
        path('reports/', my_reports_view, name='my_reports'),
        path('tools/', my_tools_view, name='my_tools'),
    ]

def my_reports_view(request):
    """Custom reports view."""
    return HttpResponse('<h1>Reports</h1>')

def my_tools_view(request):
    """Custom tools view."""
    return HttpResponse('<h1>Tools</h1>')

@hooks.register('construct_main_menu')
def add_reports_menu_item(request, menu_items):
    """Add reports to main menu."""
    menu_items.append(
        MenuItem(
            'Reports',
            reverse('my_reports'),
            icon_name='doc-full-inverse',
            order=300
        )
    )

@hooks.register('construct_main_menu')  
def add_tools_submenu(request, menu_items):
    """Add tools submenu."""
    tools_menu = Menu()
    tools_menu.register_menu_item(
        MenuItem('Tool 1', reverse('my_tools'), icon_name='cog')
    )
    
    menu_items.append(
        SubmenuMenuItem(
            'Tools',
            tools_menu,
            icon_name='cogs',
            order=400
        )
    )

Custom Form Widgets

from wagtail.admin.widgets import AdminPageChooser, AdminImageChooser
from wagtail.admin.panels import FieldPanel
from django import forms
from django.db import models

class CustomWidget(forms.TextInput):
    """Custom admin widget with special functionality."""
    template_name = 'admin/widgets/custom_widget.html'
    
    class Media:
        css = {'all': ('css/custom-widget.css',)}
        js = ('js/custom-widget.js',)

class LandingPage(Page):
    """Landing page with custom form widgets."""
    related_page = models.ForeignKey(
        'wagtailcore.Page',
        null=True,
        blank=True,
        on_delete=models.SET_NULL
    )
    hero_image = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL
    )
    special_field = models.CharField(max_length=100)
    
    content_panels = Page.content_panels + [
        FieldPanel('related_page', widget=AdminPageChooser(page_type='blog.BlogPage')),
        FieldPanel('hero_image', widget=AdminImageChooser()),
        FieldPanel('special_field', widget=CustomWidget()),
    ]

Inline Editing

from wagtail.models import Orderable
from modelcluster.fields import ParentalKey

class GalleryImage(Orderable):
    """Individual image in a gallery."""
    page = ParentalKey('GalleryPage', related_name='gallery_images', on_delete=models.CASCADE)
    image = models.ForeignKey('wagtailimages.Image', on_delete=models.CASCADE)
    caption = models.CharField(max_length=250, blank=True)
    
    panels = [
        FieldPanel('image'),
        FieldPanel('caption'),
    ]

class GalleryPage(Page):
    """Page with inline image gallery editing."""
    intro = RichTextField(blank=True)
    
    content_panels = Page.content_panels + [
        FieldPanel('intro'),
        InlinePanel(
            'gallery_images',
            label="Gallery Images",
            min_num=1,
            max_num=20,
            heading="Image Gallery"
        ),
    ]

Install with Tessl CLI

npx tessl i tessl/pypi-wagtail

docs

admin-interface.md

api.md

content-fields.md

contrib.md

index.md

media.md

page-models.md

search.md

system-integration.md

templates.md

workflows.md

tile.json