Creating page models

Wagtail provides a Page class to represent types of page (a.k.a Content types). Developers should subclass Page for their own page models.

Page uses Django’s model interface, so you can include any field type and field options that Django allows. Wagtail provides some field types of its own which simplify data entry in the Wagtail admin interface. Wagtail also wraps Django’s field types and widgets with its own concept of “Edit Handlers” and “Panels”. These further improve the data entry experience.

An example Wagtail Page Model

This example represents a typical blog post:

from django.db import models

from wagtail.wagtailcore.models import Page
from wagtail.wagtailcore.fields import RichTextField
from wagtail.wagtailadmin.edit_handlers import FieldPanel
from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
from wagtail.wagtailimages.models import Image

class BlogPage(Page):
    body = RichTextField()
    date = models.DateField("Post date")
    feed_image = models.ForeignKey(

BlogPage.content_panels = [
    FieldPanel('title', classname="full title"),
    FieldPanel('body', classname="full"),

BlogPage.promote_panels = [


To keep track of Page models and avoid class name clashes, it can be helpful to suffix model class names with “Page” e.g BlogPage, ListingIndexPage.

In the example above the BlogPage class defines three properties: body, date, and feed_image. These are a mix of basic Django models (DateField), Wagtail fields (RichTextField), and a pointer to a Wagtail model (Image).

Below that the content_panels and promote_panels lists define the capabilities and layout of the page editing interface in the Wagtail admin. The lists are filled with “panels” and “choosers”, which will provide a fine-grain interface for inputting the model’s content. The ImageChooserPanel, for instance, lets one browse the image library, upload new images and input image metadata. The RichTextField is the basic field for creating web-ready website rich text, including text formatting and embedded media like images and video. The Wagtail admin offers other choices for fields, Panels, and Choosers, with the option of creating your own to precisely fit your content without workarounds or other compromises.

Your models may be even more complex, with methods overriding the built-in functionality of the Page to achieve webdev magic. Or, you can keep your models simple and let Wagtail’s built-in functionality do the work.

Page Class Reference

Default fields

Wagtail provides some fields for the Page class by default, which will be common to all your pages. You don’t need to add these fields to your own page models however you do need to allocate them to content_panels, promote_panels or settings_panels. See above example and for further information on the panels see Displaying fields with the Editing API.

title (string, required)
Human-readable title of the page - what you’d probably use as your <h1> tag.
slug (string, required)
Machine-readable URL component for this page. The name of the page as it will appear in URLs e.g[my-slug]/
seo_title (string)
Alternate SEO-crafted title, mainly for use in the page <title> tag.
search_description (string)
SEO-crafted description of the content, used for internal search indexing, suitable for your page’s <meta name="description"> tag.
show_in_menus (boolean)
Toggles whether the page should be considered for inclusion in any site-wide menus you create.
go_live_at (datetime)
A datetime on which the page should be automatically made published (made publicly accessible)
expire_at (datetime)
A datetime on which the page should be unpublished, rendering it inaccessible to the public.

Page Attributes, Properties and Methods Reference

In addition to the model fields provided, Page has many properties and methods that you may wish to reference, use, or override in creating your own models. Those listed here are relatively straightforward to use, but consult the Wagtail source code for a full view of what’s possible.

class wagtail.wagtailcore.models.Page(id, path, depth, numchild, title, slug, content_type_id, live, has_unpublished_changes, url_path, owner_id, seo_title, show_in_menus, search_description, go_live_at, expire_at, expired)

Decorator that converts a method with a single self argument into a property cached on the instance.


Decorator that converts a method with a single self argument into a property cached on the instance.


Return the ‘most appropriate’ URL for referring to this page from the pages we serve, within the Wagtail backend and actual website templates; this is the local URL (starting with ‘/’) if we’re only running a single site (i.e. we know that whatever the current page is being served from, this link will be on the same domain), and the full URL (with domain) if not. Return None if the page is not routable.


Return the full URL (including protocol / domain) to this page, or None if it is not routable

classmethod get_verbose_name()

Returns the human-readable “verbose name” of this page model e.g “Blog page”.


Return the ‘most appropriate’ URL for this page taking into account the site we’re currently on; a local URL if the site matches, or a fully qualified one otherwise. Return None if the page is not routable.


Return true if it’s meaningful to browse subpages of this page - i.e. it currently has subpages, or it’s at the top level (this rule necessary for empty out-of-the-box sites to have working navigation)

route(request, path_components)
serve(request, *args, **kwargs)
get_context(request, *args, **kwargs)
get_template(request, *args, **kwargs)

A list of (internal_name, display_name) tuples for the modes in which this page can be displayed for preview/moderation purposes. Ordinarily a page will only have one display mode, but subclasses of Page can override this - for example, a page containing a form might have a default view of the form, and a post-submission ‘thankyou’ page

serve_preview(request, mode_name)

Return an HTTP response for use in page previews. Normally this would be equivalent to self.serve(request), since we obviously want the preview to be indicative of how it looks on the live site. However, there are a couple of cases where this is not appropriate, and custom behaviour is required:

1) The page has custom routing logic that derives some additional required args/kwargs to be passed to serve(). The routing mechanism is bypassed when previewing, so there’s no way to know what args we should pass. In such a case, the page model needs to implement its own version of serve_preview.

2) The page has several different renderings that we would like to be able to see when previewing - for example, a form page might have one rendering that displays the form, and another rendering to display a landing page when the form is posted. This can be done by setting a custom preview_modes list on the page model - Wagtail will allow the user to specify one of those modes when previewing, and pass the chosen mode_name to serve_preview so that the page model can decide how to render it appropriately. (Page models that do not specify their own preview_modes list will always receive an empty string as mode_name.)

Any templates rendered during this process should use the ‘request’ object passed here - this ensures that request.user and other properties are set appropriately for the wagtail user bar to be displayed. This request will always be a GET.

classmethod search(query_string, show_unpublished=False, search_title_only=False, extra_filters={}, prefetch_related=[], path=None)

A list of fields to be indexed by the search engine. See Search docs For Python developers


A whitelist of page models which can be created as children of this page type e.g a BlogIndex page might allow BlogPage, but not JobPage e.g

class BlogIndex(Page):
    subpage_types = ['mysite.BlogPage', 'mysite.BlogArchivePage']

Defines which template file should be used to render the login form for Protected pages using this model. This overrides the default, defined using PASSWORD_REQUIRED_TEMPLATE in your settings. See Private pages


Friendly model names

Make your model names more friendly to users of Wagtail using Django’s internal Meta class with a verbose_name e.g

class HomePage(Page):

    class Meta:
        verbose_name = "Homepage"

When users are given a choice of pages to create, the list of page types is generated by splitting your model names on each of their capital letters. Thus a HomePage model would be named “Home Page” which is a little clumsy. verbose_name as in the example above, would change this to read “Homepage” which is slightly more conventional.

The above example also ensures the name of the

Helpful model descriptions

As your site becomes more complex users may require some prompting in deciding which content type to use when creating a new page. Developers can add a description to their Models by extending Django’s internal model Meta class.

Insert the following once at the top of your

import django.db.models.options as options
options.DEFAULT_NAMES = options.DEFAULT_NAMES + ('description',)

Then for each model as necessary, add a description option to the model Meta class

class HomePage(Page):

    class Meta:
        description = "The top level homepage for your site"
        verbose_name = "Homepage"

(This method can be used to extend the Model Meta class in various ways however Wagtail only supports the addition of a description option).