Backend Checklist¶
A non-exhaustive list of things to watch out for when reviewing.
Database Schema Changes¶
- Column renames, drops, and table removals follow the multi-release process
- No migration drops a column or table that is still referenced in code
- Data migrations handle both forward and reverse (or explicitly use
RunPython.noopwith a comment explaining why) - StreamField data migrations also update Revision objects, not just live pages
Caching¶
-
SimpleDictCachestores object references, not copies - mutating an object retrieved from this cache also mutates the cached value. Confirm this is not a risk, or that the risk is handled.
Code Style¶
- Inline imports include a comment explaining which circular import they avoid
Feature Switches¶
- New waffle switches exist in the database - undefined switches default to ON in dev but OFF in production.
Middleware¶
- New middleware is placed at the correct position in
MIDDLEWARE- the list is order-sensitive, some entries are conditionally inserted at a specific index (not appended), andWAGTAIL_ENABLE_ADMINinserts auth/session middleware at position 3 - Middleware that should only be active under certain conditions uses the
MiddlewareNotUsedpattern in__init__to self-disable, rather than conditional logic in__call__
Migrations¶
-
Ensure that
RunPythondata migrations useapps.get_model()rather than importing the model class directly - direct imports reflect the current model definition, not the historical state at the point the migration runs, which can cause failures after subsequent model changes -
StreamField block restructures use Wagtail's
MigrateStreamDatautility andBaseBlockOperationsubclasses rather than hand-rolling JSON manipulation - the built-in utilities handle nested structures and edge cases correctly
Performance and Queries¶
- New views and querysets are checked for N+1 queries - Wagtail page trees, StreamField content, and snippet references are common sources
Settings and Environment¶
-
DEV=Trueis not the same asDEBUG=True-DEVrefers to a mode of operation of the websites, usually governing what cut of data gets pulled in to be shown.DEV=Truesetting covers Dev and Demos. Test, Staging and Prod runDEV=False. In rare cases, gate production-only behaviour by usingPROD=True - Remember that the Web deployment only has readonly access to the DB. The CMS deployment has read-write access.
-
request.sessionis not available by default - session middleware is only added whenWAGTAIL_ENABLE_ADMIN=True
URLs and Views¶
- Views being migrated to the CMS use
prefer_cmson aTemplateView, not on apage()helper (which is unsupported byprefer_cms) - Views being migrated to the CMS may need to be added to
cms_only_urls.pyin order to avoid breaking pages that look them up viareverse()orurl() - New non-locale URL path prefixes are added to
SUPPORTED_NONLOCALESin settings - omitting them causes the path to be inadvertently locale-prefixed and then 404 in production
Wagtail CMS¶
- New page models are added to
CMS_ALLOWED_PAGE_MODELSin settings - dev uses["__all__"]so omissions are invisible locally but will break in production - New page models are added to
./bin/export-db-to-sqlite.sh- failing to do so will create an incomplete export of Page models but no corresponding custom page class -
ftl_filesattribute is set on new page models - missing references don't error, strings just appear untranslated -
on_deleteis intentional on ForeignKeys -PROTECTfor things that must not be deletable while in use,SET_NULLfor optional references - ForeignKeys to images and snippets set
related_name="+"where the reverse relation isn't needed - without it, Django auto-generates a reverse accessor that clutters the ORM and can shadow other relations - Image renditions used in templates are within the pre-generated size range - production has read-only storage and cannot generate renditions on the fly
- All StreamFields have
use_json_field=True- required since Wagtail v5, omitting it will cause errors on future upgrades - Leaf page models must set
subpage_types = []; models with page-type heirarchy constraints should just setparent_page_types - Singleton page models have
max_count = 1to prevent duplicate creation in the CMS - New page models set an explicit
templateattribute - without one, Wagtail auto-generates a path that may not match the project's template directory layout
Wagtail Localize¶
- New snippet models intended for translation include
TranslatableMixin(andDraftStateMixin/RevisionMixinif they need draft support) - omitting these means the content can't be translated via Wagtail Localize - Snippet querysets used in front-end views call
.live()- without it, draft content can be surfaced to users - Translatable page and snippet models mark
slug(and any other fields that must stay in sync across locales) asSynchronizedField- without this, slugs get sent for translation and break URL routing
Wagtail Internals¶
- Any PR that bumps the Wagtail version must check over the monkey-patches in
cms/apps.pyready()- these patch Wagtail internals that could be moved, renamed, or fixed upstream without warning - New CMS admin URL paths (e.g.
_documents; paths to JS endpoints) are added toSUPPORTED_NONLOCALESconditionally alongside the existingWAGTAIL_ENABLE_ADMINblock - this is to avoid admin paths becoming incorrectly and inviably prefixed