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

page-models.mddocs/

Page Models and Content Structure

Core page functionality providing the foundation for all content in Wagtail. The Page model hierarchy enables tree-based content organization with powerful inheritance and customization capabilities.

Capabilities

Base Page Model

The core Page model provides the foundation for all pages in Wagtail, including hierarchical structure, URL routing, publishing workflow, and content management.

class Page(
    WorkflowMixin,
    PreviewableMixin, 
    DraftStateMixin,
    LockableMixin,
    RevisionMixin,
    TranslatableMixin,
    SpecificMixin,
    MP_Node,
    index.Indexed,
    ClusterableModel
):
    """
    Base page model with full CMS functionality.
    
    Core Fields:
        title (str): Page title
        draft_title (str): Draft version of title (auto-managed)
        slug (str): URL slug for the page
        content_type (ForeignKey): Content type for polymorphic behavior
        url_path (str): Full URL path from site root (auto-managed)
        seo_title (str): SEO-optimized title
        search_description (str): Meta description for search engines
        show_in_menus (bool): Whether page appears in navigation
        owner (User): Page owner for permissions
        
    Publishing Fields (from DraftStateMixin):
        live (bool): Whether page is published and visible
        has_unpublished_changes (bool): Whether there are unpublished changes
        first_published_at (datetime): When page was first published
        last_published_at (datetime): When page was last published
        latest_revision_created_at (datetime): When latest revision was created
        go_live_at (datetime): Scheduled publish time
        expire_at (datetime): Scheduled expiration time
        expired (bool): Whether page has expired
        live_revision (ForeignKey): Currently live revision
        
    Locking Fields (from LockableMixin):
        locked (bool): Whether page is locked for editing
        locked_by (User): User who locked the page
        locked_at (datetime): When page was locked
        
    Revision Fields (from RevisionMixin):
        latest_revision (ForeignKey): Most recent revision
        
    Translation Fields (from TranslatableMixin):
        locale (ForeignKey): Language/locale for this page
        translation_key (UUID): Links translations together
        
    Tree Fields (from MP_Node):
        path (str): Tree path for hierarchical queries
        depth (int): Tree depth level
        numchild (int): Number of direct children
        
    Other Fields:
        alias_of (ForeignKey): Original page if this is an alias
    """
    # Core fields
    title: str
    draft_title: str
    slug: str
    content_type: ContentType
    url_path: str
    seo_title: str
    search_description: str
    show_in_menus: bool
    owner: User
    
    # Publishing state (DraftStateMixin)
    live: bool
    has_unpublished_changes: bool
    first_published_at: datetime
    last_published_at: datetime
    latest_revision_created_at: datetime
    go_live_at: datetime
    expire_at: datetime
    expired: bool
    live_revision: Revision
    
    # Locking (LockableMixin)
    locked: bool
    locked_by: User
    locked_at: datetime
    
    # Revisions (RevisionMixin)
    latest_revision: Revision
    
    # Translation (TranslatableMixin)
    locale: Locale
    translation_key: UUID
    
    # Tree structure (MP_Node)
    path: str
    depth: int
    numchild: int
    
    # Aliases
    alias_of: Page
    
    # URL and routing methods
    def get_url(self, request=None, current_site=None):
        """Get the URL for this page."""
    
    def get_full_url(self, request=None):
        """Get the absolute URL including domain for this page."""
    
    def route(self, request, path_components):
        """Route a request to this page or its descendants."""
    
    def set_url_path(self, parent):
        """Update the url_path field based on this page's slug and parent."""
    
    @classmethod
    def route_for_request(cls, request, path):
        """Find the page to serve for the given request path."""
    
    @classmethod  
    def find_for_request(cls, request, path):
        """Find page matching the request, returns (page, args, kwargs)."""
    
    # Content serving methods
    def serve(self, request):
        """Serve this page for the given request."""
    
    def get_context(self, request):
        """Get template context for rendering this page."""
    
    def get_template(self, request, *args, **kwargs):
        """Get template for rendering this page."""
    
    # Admin interface methods
    def get_admin_display_title(self):
        """Get title for display in admin interface."""
    
    def get_admin_base_path(self):
        """Get the base path for admin URLs for this page."""
    
    # Lifecycle methods
    def save(self, *args, **kwargs):
        """Save the page, updating URL paths and search index."""
    
    def delete(self):
        """Delete the page and all its descendants."""
    
    def clean(self):
        """Validate the page before saving."""
    
    # Content management methods  
    def copy(self, recursive=False, to=None, update_attrs=None, copy_revisions=True):
        """Create a copy of this page."""
    
    def move(self, target, pos=None):
        """Move this page to a new location in the tree."""
    
    def update_aliases(self, *, revision=None, _content_json=None, user=None):
        """Update any aliases of this page with new content."""
    
    # Tree traversal methods
    def get_children(self):
        """Get direct children of this page."""
    
    def get_descendants(self, inclusive=False):
        """Get all descendants of this page."""
    
    def get_ancestors(self, inclusive=False):
        """Get all ancestors of this page."""
    
    def get_siblings(self, inclusive=False):
        """Get sibling pages at the same level."""
    
    def is_site_root(self):
        """Check if this page is the root of a site."""
    
    # Validation methods
    @classmethod
    def can_exist_under(cls, parent):
        """Check if this page type can be created under the parent."""
    
    @classmethod
    def can_create_at(cls, parent):
        """Check if this page type can be created under the parent."""
    
    def can_move_to(self, parent):
        """Check if this page can be moved under the parent."""
    
    @classmethod
    def allowed_parent_page_models(cls):
        """Get allowed parent page models for this page type."""
    
    @classmethod
    def allowed_subpage_models(cls):
        """Get allowed subpage models under this page type."""
    
    # Permission methods
    def permissions_for_user(self, user):
        """Get permission tester for the given user."""
        
    def get_view_restrictions(self):
        """Get view restrictions applying to this page."""
    
    # Workflow methods
    def get_workflow(self):
        """Get the workflow assigned to this page."""
    
    # SEO and sitemap methods
    def get_sitemap_urls(self, request=None):
        """Get URLs for XML sitemap generation."""
    
    # Caching methods
    def get_cache_key_components(self):
        """Get components for generating cache keys."""
    
    # HTTP method validation
    @classmethod
    def allowed_http_method_names(cls):
        """Get allowed HTTP methods for this page type."""

Model Mixins

Mixins that provide specific functionality for custom models and pages.

class RevisionMixin:
    """
    Adds revision capabilities to models.
    
    Methods provide version control and content history.
    """
    def save_revision(self, user=None, approved_go_live_at=None, changed=True, log_action=False, previous_revision=None, clean=True):
        """
        Save a new revision of this object.
        
        Parameters:
            user: User who made the changes
            approved_go_live_at: When changes should go live
            changed: Whether content has changed
            log_action: Whether to log this action
            previous_revision: Previous revision for comparison
            clean: Whether to clean the object before saving
        """
    
    def get_latest_revision(self):
        """Get the most recent revision."""
    
    def get_latest_revision_as_object(self):
        """Get the content of the latest revision as an object."""

class DraftStateMixin:
    """
    Adds draft/live state management to models.
    
    Provides publishing workflow capabilities.
    """
    live: bool
    has_unpublished_changes: bool
    first_published_at: datetime
    last_published_at: datetime
    go_live_at: datetime
    expire_at: datetime
    expired: bool
    live_revision: Revision
    
    def publish(self, revision=None, user=None):
        """Publish this content, making it live."""
    
    def unpublish(self, set_expired=False, commit=True, user=None):
        """Remove this content from live site."""
    
    def get_latest_revision_as_object(self):
        """Get latest revision content as object (overrides RevisionMixin)."""
    
    def get_scheduled_revision_as_object(self):
        """Get scheduled revision if one exists."""
    
    @property
    def status_string(self):
        """Get human-readable status for admin display."""

class LockableMixin:
    """
    Adds content locking functionality to prevent concurrent editing.
    """
    locked: bool
    locked_by: User
    locked_at: datetime
    
    def get_lock(self):
        """Get lock object if this content is locked."""
    
    def with_content_json(self, content):
        """Return a copy with the given content restored."""

class WorkflowMixin:
    """
    Adds workflow support for approval processes.
    """
    @property
    def current_workflow_task_state(self):
        """Get current workflow task state."""
    
    @property
    def current_workflow_task(self):
        """Get current workflow task."""
    
    @property  
    def workflow_states(self):
        """Get all workflow states for this content."""
    
    @classmethod
    def get_default_workflow(cls):
        """Get default workflow for this content type."""
    
    def get_workflow(self):
        """Get the workflow assigned to this content."""

class PreviewableMixin:
    """
    Adds preview functionality for draft content.
    """
    @property
    def preview_modes(self):
        """Get available preview modes."""
    
    @property
    def preview_sizes(self):
        """Get available preview sizes."""
    
    def serve_preview(self, request, mode_name):
        """Serve a preview of this content."""
    
    def make_preview_request(self, request=None, mode_name=''):
        """Create a fake request for previewing content."""
    
    def get_preview_context(self, request, mode_name):
        """Get context for preview rendering."""
    
    def get_preview_template(self, request, mode_name):
        """Get template for preview rendering."""
    
    def is_previewable(self):
        """Check if this content can be previewed."""

class TranslatableMixin:
    """
    Adds translation support for multi-language content.
    """
    locale: Locale
    translation_key: UUID
    
    def get_translations(self, inclusive=False):
        """Get all translations of this content."""
    
    def copy_for_translation(self, locale):
        """Create a copy for translation to another locale."""

Content Management Models

Models for managing content lifecycle, organization, and access control.

class Revision:
    """
    Represents a saved version of page or model content.
    """
    content_object: Model
    base_content_type: ContentType
    object_str: str
    created_at: datetime
    user: User
    approved_go_live_at: datetime
    
    def as_object(self):
        """Return the content of this revision as a model instance."""
    
    def publish(self):
        """Publish this revision, making it live."""
    
    def is_latest_revision(self):
        """Check if this is the latest revision."""
    
    def get_previous(self):
        """Get the previous revision."""
    
    def get_next(self):
        """Get the next revision."""

class Collection:
    """
    Organizes media and content with hierarchical permissions.
    """
    name: str
    path: str
    
    def get_descendants(self, inclusive=False):
        """Get all descendant collections."""
    
    def get_ancestors(self, inclusive=False):
        """Get all ancestor collections."""
    
    def get_view_restrictions(self):
        """Get view restrictions for this collection."""

class Site:
    """
    Represents a website with its own domain and root page.
    """
    hostname: str
    port: int
    site_name: str
    root_page: Page
    root_url: str
    
    @classmethod
    def find_for_request(cls, request):
        """Find the Site object for the given HTTP request."""
    
    @classmethod
    def get_site_root_paths(cls):
        """Get URL paths for all site root pages."""

class Locale:
    """
    Represents a language/region combination for internationalization.
    """
    language_code: str
    region_code: str
    
    @classmethod
    def get_default(cls):
        """Get the default locale for the site."""
    
    @classmethod
    def get_active(cls):
        """Get all active locales."""

Permission Models

Models for managing user permissions and access control.

class GroupPagePermission:
    """
    Assigns page permissions to user groups.
    """
    group: Group
    page: Page
    permission: Permission
    
    objects: GroupPagePermissionManager

class PageViewRestriction:
    """
    Restricts page viewing to specific users or groups.
    """
    page: Page
    restriction_type: str  # 'password', 'groups', 'login'
    password: str
    groups: ManyToManyField[Group]
    
    def save(self, **kwargs):
        """Save with audit logging."""
    
    def delete(self, **kwargs):
        """Delete with audit logging."""

class PagePermissionTester:
    """
    Utility class for testing user permissions on pages.
    """
    def __init__(self, user, page):
        """Initialize with user and page to test."""
    
    def can_edit(self):
        """Check if user can edit the page."""
    
    def can_delete(self):
        """Check if user can delete the page."""
    
    def can_publish(self):
        """Check if user can publish the page."""
    
    def can_unpublish(self):
        """Check if user can unpublish the page."""

Usage Examples

Creating Custom Page Models

from wagtail.models import Page
from wagtail.fields import RichTextField
from wagtail.admin.panels import FieldPanel
from django.db import models

class BlogPage(Page):
    """Custom page model for blog posts."""
    date = models.DateField("Post date")
    intro = models.CharField(max_length=250)
    body = RichTextField(blank=True)
    
    content_panels = Page.content_panels + [
        FieldPanel('date'),
        FieldPanel('intro'),
        FieldPanel('body'),
    ]
    
    def get_context(self, request):
        context = super().get_context(request)
        context['recent_posts'] = BlogPage.objects.live().order_by('-date')[:5]
        return context

Working with Page Hierarchy

# Get all pages under a section
section_page = Page.objects.get(slug='news')
news_articles = section_page.get_children().live().order_by('-first_published_at')

# Move a page to a new parent
page_to_move = Page.objects.get(slug='old-location')
new_parent = Page.objects.get(slug='new-section')
page_to_move.move(new_parent, pos='last-child')

# Copy a page with all its content
original_page = Page.objects.get(slug='template-page')
copied_page = original_page.copy(
    recursive=True,  # Copy child pages too
    update_attrs={'title': 'New Page Title', 'slug': 'new-page-slug'}
)

Using Mixins for Custom Models

from wagtail.models import RevisionMixin, DraftStateMixin
from django.db import models

class Article(RevisionMixin, DraftStateMixin, models.Model):
    """Custom model with revision and publishing capabilities."""
    title = models.CharField(max_length=255)
    content = models.TextField()
    
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        # Save revision after saving the model
        self.save_revision()
    
    def go_live(self):
        """Publish this article."""
        self.live = True
        self.save()
        self.publish()

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