Each page type (a.k.a. content type) in Wagtail is represented by a Django model. All page models must inherit from the {class}`wagtail.models.Page` class.
As all page types are Django models, you can use any field type that Django provides. See [Model field reference](django:ref/models/fields) for a complete list of field types you can use. Wagtail also provides `wagtail.fields.RichTextField` which provides a WYSIWYG editor for editing rich-text content.
Ensure that none of your field names are the same as your class names. This will cause errors due to the way Django handles relations ([read more](https://github.com/wagtail/wagtail/issues/503)). In our examples we have avoided this by appending "Page" to each model name.
Each Wagtail page type is a Django model, represented in the database as a separate table.
Each page type can have its own set of fields. For example, a news article may have body text and a published date, whereas an event page may need separate fields for venue and start/finish times.
In Wagtail, you can use any Django field class. Most field classes provided by third party apps should work as well.
Wagtail also provides a couple of field classes of its own:
-`RichTextField` - For rich text content
-`StreamField` - A block-based content field (see: [Freeform page content using StreamField](./streamfield))
For tagging, Wagtail fully supports [django-taggit](https://django-taggit.readthedocs.org/en/latest/) so we recommend using that.
### Search
The `search_fields` attribute defines which fields are added to the search index and how they are indexed.
This should be a list of `SearchField` and `FilterField` objects. `SearchField` adds a field for full-text search. `FilterField` adds a field for filtering the results. A field can be indexed with both `SearchField` and `FilterField` at the same time (but only one instance of each).
In the above example, we've indexed `body` for full-text search and `date` for filtering.
The arguments that these field types accept are documented in [indexing extra fields](wagtailsearch_indexing_fields).
### Editor panels
There are a few attributes for defining how the page's fields will be arranged in the page editor interface:
-`content_panels` - For content, such as main body text
-`promote_panels` - For metadata, such as tags, thumbnail image and SEO title
-`settings_panels` - For settings, such as publish date
These allow editing of model fields. The `FieldPanel` class will choose the correct widget based on the type of the field, such as a rich text editor for `RichTextField`, or an image chooser for a `ForeignKey` to an image model. `FieldPanel` also provides a page chooser interface for `ForeignKey`s to page models, but for more fine-grained control over which page types can be chosen, `PageChooserPanel` provides additional configuration options.
These two attributes allow you to control where page types may be used in your site. They allow you to define rules like "blog entries may only be created under a blog index".
Both parent and subpage types take a list of model classes or model names. Model names are of the format `app_label.ModelName`. If the `app_label` is omitted, the same app is assumed.
With every Wagtail Page you are able to add a helpful description text, similar to a `help_text` model attribute. By adding `page_description` to your Page model you'll be adding a short description that can be seen when you create a new page, edit an existing page or when you're prompted to select a child page type.
The most common method of retrieving page URLs is by using the [`{% pageurl %}`](pageurl_tag) or [`{% fullpageurl %}`](fullpageurl_tag) template tags. Since it's called from a template, these automatically includes the optimizations mentioned below.
Page models also include several low-level methods for overriding or accessing page URLs.
#### Customising URL patterns for a page model
The `Page.get_url_parts(request)` method will not typically be called directly, but may be overridden to define custom URL routing for a given page model. It should return a tuple of `(site_id, root_url, page_path)`, which are used by `get_url` and `get_full_url` (see below) to construct the given type of page URL.
When overriding `get_url_parts()`, you should accept `*args, **kwargs`:
You can call the `Page.get_url(request)` method whenever you need a page URL. It defaults to returning local URLs (not including the protocol or domain) if it determines that the page is on the current site (via the hostname in `request`); otherwise, it would return a full URL including the protocol and domain. Whenever possible, you should include the optional `request` argument to enable per-request caching of site-level URL information and facilitate the generation of local URLs.
A common use case for `get_url(request)` is in any custom template tag your project may include for generating navigation menus. When writing such a custom template tag, ensure that it includes `takes_context=True` and uses `context.get('request')` to safely pass the
To retrieve the full URL (including the protocol and domain), use `Page.get_full_url(request)`. Whenever possible, the optional `request` argument should be included to enable per-request caching of site-level URL information.
Each page model can be given an HTML template which is rendered when a user browses to a page on the site frontend. This is the simplest and most common way to get Wagtail content to end users (but not the only way).
### Adding a template for a page model
Wagtail automatically chooses a name for the template based on the app label and model class name.
For example, the template for the above blog page will be: `blog/blog_page.html`
You just need to create a template in a location where it can be accessed with this name.
### Template context
Wagtail renders templates with the `page` variable bound to the page instance being rendered. Use this to access the content of the page. For example, to get the title of the current page, use `{{ page.title }}`. All variables provided by [context processors](https://docs.djangoproject.com/en/stable/ref/templates/api/#subclassing-context-requestcontext) are also available.
#### Customising template context
All pages have a `get_context` method that is called whenever the template is rendered and returns a dictionary of variables to bind into the template.
To add more variables to the template context, you can override this method:
Set the `template` attribute on the class to use a different template file:
```python
class BlogPage(Page):
...
template = 'other_template.html'
```
#### Dynamically choosing the template
The template can be changed on a per-instance basis by defining a `get_template` method on the page class. This method is called every time the page is rendered:
In this example, pages that have the `use_other_template` boolean field set will use the `blog/other_blog_page.html` template. All other pages will use the default `blog/blog_page.html`.
#### Ajax Templates
If you want to add AJAX functionality to a page, such as a paginated listing that updates in-place on the page rather than triggering a full page reload, you can set the `ajax_template` attribute to specify an alternative template to be used when the page is requested via an AJAX call (as indicated by the `X-Requested-With: XMLHttpRequest` HTTP header):
```python
class BlogPage(Page):
...
ajax_template = 'other_template_fragment.html'
template = 'other_template.html'
```
### More control over page rendering
All page classes have a `serve()` method that internally calls the `get_context` and `get_template` methods and renders the template. This method is similar to a Django view function, taking a Django `Request` object and returning a Django `Response` object.
This method can also be overridden for complete control over page rendering.
For example, here's a way to make a page respond with a JSON representation of itself:
```python
from django.http import JsonResponse
class BlogPage(Page):
...
def serve(self, request):
return JsonResponse({
'title': self.title,
'body': self.body,
'date': self.date,
# Resizes the image to 300px width and gets a URL to it
Wagtail allows the nesting of other models within a page. This is useful for creating repeated fields, such as related links or items to display in a carousel. Inline model content is also versioned with the rest of the page.
The model inlining feature is provided by [django-modelcluster](https://github.com/wagtail/django-modelcluster) and the `ParentalKey` field type must be imported from there:
In the above example, related links are defined as a child object on the `BlogPage` page type. Often, the same kind of inline child object will appear on several page types, and in these cases, it's undesirable to repeat the entire model definition. This can be avoided by refactoring the common fields into an abstract model:
Alternatively, if RelatedLink is going to appear on a significant number of the page types defined in your project, it may be more appropriate to set up a single `RelatedLink` model pointing to the base `wagtailcore.Page` model:
This will then make `related_links` available as a relation across all page types, although it will still only be editable on page types that include the `InlinePanel` in their panel definitions - for other page types, the set of related links will remain empty.
Wagtail uses Django's [multi-table inheritance](https://docs.djangoproject.com/en/stable/topics/db/models/#multi-table-inheritance) feature to allow multiple page models to be used in the same tree.
Each page is added to both Wagtail's built-in {class}`~wagtail.models.Page` model as well as its user-defined model (such as the `BlogPage` model created earlier).
When working with multiple page types together, you will typically use instances of Wagtail's `Page` model, which don't give you access to any fields specific to their type.
When working with a single page type, you can work with instances of the user-defined model. These give access to all the fields available in `Page`, along with any user-defined fields for that type.
You can convert a `Page` object to its more specific user-defined equivalent using the `.specific` property. This may cause an additional database lookup.
```python
>>> page = Page.objects.get(title="A Blog post")
>>> page
<Page:ABlogpost>
# Note: the blog post is an instance of Page so we cannot access body, date or feed_image
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. Defining `verbose_name` as in the example above would change this to read "Homepage", which is slightly more conventional.
`Page`-derived models _cannot_ be given a default ordering by using the standard Django approach of adding an `ordering` attribute to the internal `Meta` class.