In a recent project, I wanted to add a Wagtail page type which just redirects to another URL. By doing this, you can query the page, you can make it pop up in menus and you can easily update the URL to which it needs to redirect.

The perfect candidate to make a separate page type for. As explained in a previous post, I tend to group these type of models in an app called base.

The model I created for the redirector page is:

base/models.py

from django.db import models
from django.shortcuts import redirect
from django.utils.html import format_html

from wagtail.core.models import Page

class RedirectorPage(Page):
    redirect_to = models.URLField(
        help_text='The URL to redirect to',
        blank=False,
    )

    content_panels = Page.content_panels + [
        FieldPanel('redirect_to', classname="full"),
    ]

    def get_admin_display_title(self):
        return format_html(f"{self.draft_title}<br/>➡️ {self.redirect_to}")

    class Meta:
        verbose_name = 'Redirector'

    def get_url(self, request=None, current_site=None):
        return self.redirect_to

    def get_full_url(self, request=None, current_site=None):
        return self.redirect_to

    def serve(self, request):
        return redirect(self.redirect_to)

The first thing I did was to create an URL field called redirect_to which contains the URL to redirect to. This field is also added to the default content panels of the page.

I also declared the get_admin_display_title method. This is the method used by the admin interface to get the title for the item. I've added the URL to the draft title to make it easy to see this in the admin UI. We are using the format_html function which allows us to return a HTML blob instead of a plain text string.

By adding a Meta subclass, I declared verbose_name to specify how the page model should be named in the admin UI (e.g. in the list where you select which type of page you want to add.

The get_url and get_full_url functions are used by Wagtail to get the relative and full URLs to the page. In our case, the redirect URL is returned.

Lastly, we override the serve method of the page. This is the method used internally by Wagtail to render the page. There is also an equivalent serve_preview which is used for previewing pages. Unless you override it, it's equivalent to self.serve(request). What I did in that function to perform the redirect is to use Django's redirect shortcut function to redirect to the URL.

After you defined the model, don't forget to run makemigrations and migrate to load the model into the database:

$ ./manage.py makemigrations
$ ./manage.py migrate