DraftStateMixin with commit=True deletes child relations not in form panel
Issue summary
In Wagtail 7.0, unpublished DraftStateMixin objects have commit=True passed to form.save(), which triggers modelcluster to synchronize child relations to match the in-memory form state. If a ClusterableModel has ParentalKey child relations that are NOT included in the form panels, those relationships get deleted from the database on every draft save.
Version
Wagtail 7.0.9 (issue introduced in Wagtail 7.0.0) Django 5.2 modelcluster 6.x
Root Cause
In wagtail/admin/views/generic/mixins.py, line 508: commit=self.view_name == "edit" and not self.object.live This condition evaluates to True for ANY unpublished object being edited, not just brand-new objects. When commit=True: form.save(commit=True) calls the real instance.save() with no update_fields parameter modelcluster sees a full save and synchronizes all child relations Child relations not in the form are set to their in-memory state (empty/not populated by the form) The sync deletes relationships that existed in the database
Steps to reproduce
- Create a custom ClusterableModel with DraftStateMixin, e.g.
class MyClusterableModel(DraftStateMixin, ClusterableModel):
pass- Add a ParentalKey child relation e.g.
class MyOtherClusterableModel(ClusterableModel):
cb = ParentalKey(MyClusterableModel, related_name="my_other_cbs")- Do NOT include that child relation in the form panels
- Create and publish an instance with child relations
- Unpublish the instance
- Edit and save the instance (draft save)
- Bug: The child relations are deleted
Additional information
Additional Context
This issue was discovered during a Wagtail 5.2.6 → 7.0.9 upgrade. In Wagtail 5.2.6, the save path was: Draft saves: commit=False for all DraftStateMixin models Revisions used targeted save with update_fields Child relations not in the form were preserved In Wagtail 7.0, this changed to the conditional commit logic, which inadvertently breaks models with external child relations.
Can be reproduced
Not confirmed
Technical details
- Python version: 3.12.
- Django version: 5.2.17.
- Wagtail version: 7.0.9.
- Browser version: https://www.whatsmybrowser.org/b/44ZN4.
Working on this
If you would like to contribute to this issue, follow these steps:
- Confirm that the issue is reproducible, either on a fresh Wagtail project or the bakerydemo.
- Once confirmed, view our contributing guidelines, add a comment to the issue once you're ready to start.
Source: wagtail/wagtail