Creating page models

The Page Class

Page uses Django’s model interface, so you can include any field type and field options that Django allows. Wagtail provides some fields and editing handlers that simplify data entry in the Wagtail admin interface, so you may want to keep those in mind when deciding what properties to add to your models in addition to those already provided by Page.

Built-in Properties of the Page Class

Wagtail provides some properties in the Page class which are common to most webpages. Since you’ll be subclassing Page, you don’t have to worry about implementing them.

Public Properties

title (string, required)
Human-readable title for the content
slug (string, required)
Machine-readable URL component for this piece of content. The name of the page as it will appear in URLs e.g http://domain.com/blog/[my-slug]/
seo_title (string)
Alternate SEO-crafted title which overrides the normal title for use in the <head> of a page
search_description (string)
A SEO-crafted description of the content, used in both internal search indexing and for the meta description read by search engines

The Page class actually has alot more to it, but these are probably the only built-in properties you’ll need to worry about when creating templates for your models.

Anatomy of a Wagtail Model

So what does a Wagtail model definition look like? Here’s a model representing 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(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )

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

BlogPage.promote_panels = [
    FieldPanel('slug'),
    FieldPanel('seo_title'),
    FieldPanel('show_in_menus'),
    FieldPanel('search_description'),
    ImageChooserPanel('feed_image'),
]

To keep track of your Page-derived models, it might be helpful to include “Page” as the last part of your class name. BlogPage 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).

Next, the content_panels and promote_panels lists define the capabilities and layout of the Wagtail admin page edit interface. 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.

Now that we have a basic idea of how our content is defined, lets look at relationships between pieces of content.

Page 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)
specific

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

specific_class

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

url

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.

full_url

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

relative_url(current_site)

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.

is_navigable()

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)
preview_modes

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.

get_ancestors(inclusive=False)
get_descendants(inclusive=False)
get_siblings(inclusive=True)
classmethod search(query_string, show_unpublished=False, search_title_only=False, extra_filters={}, prefetch_related=[], path=None)

Site

Django’s built-in admin interface provides the way to map a “site” (hostname or domain) to any node in the wagtail tree, using that node as the site’s root.

Access this by going to /django-admin/ and then “Home › Wagtailcore › Sites.” To try out a development site, add a single site with the hostname localhost at port 8000 and map it to one of the pieces of content you have created.

Wagtail’s developers plan to move the site settings into the Wagtail admin interface.