At work we run a large multitenant version of Wagtail (~500 separate websites on a single
installation). To achieve this and to make some other changes to the way Wagtail behaves, we have a
number of monkey patches. So we have consolidated all of them in their own Django app which we
called wagtail_patches
. This is loaded into our INSTALLED_APPS
after most of our own apps but
before any of the Wagtail apps:
# settings.py
INSTALLED_APPS = [
# Multitenant apps. These are ordered with regard to template overrides.
'core',
'search',
'site_creator',
'calendar',
'theme_v6_5',
'theme_v7_0',
'robots_txt',
'wagtail_patches', #####
'sitemap',
'features',
'custom_auth',
# Wagtail apps.
'wagtail.embeds',
'wagtail.sites',
'wagtail.users',
'wagtail.snippets',
'wagtail.documents',
# We use a custom replacement for wagtail.images that makes it add decoding="async" and loading="lazy" attrs.
# 'wagtail.images',
'wagtail_patches.apps.MultitenantImagesAppConfig',
'wagtail.search',
'wagtail.admin',
'wagtail',
'wagtail.contrib.modeladmin',
'wagtail.contrib.settings',
'wagtail.contrib.routable_page',
# Wagtail dependencies, django, etc.....
]
And then in that app, we use the apps.py
file to load everything from the patches directory:
from django.apps import AppConfig
from wagtail.images.apps import WagtailImagesAppConfig
class WagtailPatchesConfig(AppConfig):
name = 'wagtail_patches'
verbose_name = 'Wagtail Patches'
ready_is_done = False
# If there are multiple AppConfigs in a single apps.py, one of them needs to be default=True.
default = True
def ready(self):
"""
This function runs as soon as the app is loaded. It executes our monkey patches to various parts of Wagtail
that change it to support our architecture of fully separated tenants.
"""
# As suggested by the Django docs, we need to make absolutely certain that this code runs only once.
if not self.ready_is_done:
# The act of performing this import executes all the code in patches/__init__.py.
from . import patches # noqa
self.ready_is_done = True
else:
print("{}.ready() executed more than once! This method's code is skipped on subsequent runs.".format(
self.__class__.__name__
))
class MultitenantImagesAppConfig(WagtailImagesAppConfig):
default_attrs = {"decoding": "async", "loading": "lazy"}
You will note that the first of our customizations is right in apps.py
. We use this file to
configure default html attributes for image tags generated by Wagtail - per the instructions in
“Adding default attributes to all images”.