From cfcfd855255c134838a5a91d0ff79be3c6d685ff Mon Sep 17 00:00:00 2001 From: Sage Abdullah Date: Fri, 10 Mar 2023 17:17:24 +0000 Subject: [PATCH] Clarify ClusterableModel requirements for using relations with RevisionMixin-enabled models --- CHANGELOG.txt | 3 +++ docs/releases/4.1.3.md | 4 ++++ docs/releases/4.2.1.md | 4 ++++ docs/releases/5.0.md | 1 + docs/topics/snippets.md | 24 ++++++++++++++++-------- 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 838a88881b..c40d622d97 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -50,6 +50,7 @@ Changelog * Docs: Improve documentation for InlinePanel (Vallabh Tiwari) * Docs: Add contributor guidelines for building Stimulus Controllers (Thibaud Colas, Loveth Omokaro, LB (Ben) Johnston) * Docs: Fix typo in "Extending Draftail" documentation (Hans Kelson) + * Docs: Clarify `ClusterableModel` requirements for using relations with `RevisionMixin`-enabled models (Sage Abdullah) * Maintenance: Removed features deprecated in Wagtail 3.0 and 4.0 (Matt Westcott) * Maintenance: Update djhtml (html formatting) library to v 1.5.2 (Loveth Omokaro) * Maintenance: Re-enable `strictPropertyInitialization` in tsconfig (Thibaud Colas) @@ -87,6 +88,7 @@ Changelog * Fix: Fix dialog component's message to have rounded corners at the top side (Sam) * Fix: Prevent matches from unrelated models from leaking into SQLite FTS searches (Matt Westcott) * Fix: Prevent duplicate addition of StreamField blocks with the new block picker (Deepam Priyadarshi) + * Docs: Clarify `ClusterableModel` requirements for using relations with `RevisionMixin`-enabled models (Sage Abdullah) * Maintenance: Update Algolia DocSearch to use new application and correct versioning setup (Thibaud Colas) @@ -253,6 +255,7 @@ Changelog * Fix: Add missing log information for `wagtail.schedule.cancel` (Stefan Hammer) * Fix: Fix timezone activation leaking into subsequent requests in `require_admin_access()` (Stefan Hammer) * Fix: Prevent matches from unrelated models from leaking into SQLite FTS searches (Matt Westcott) + * Docs: Clarify `ClusterableModel` requirements for using relations with `RevisionMixin`-enabled models (Sage Abdullah) * Maintenance: Update Algolia DocSearch to use new application and correct versioning setup (Thibaud Colas) diff --git a/docs/releases/4.1.3.md b/docs/releases/4.1.3.md index de0e7c8eab..0f67eccf71 100644 --- a/docs/releases/4.1.3.md +++ b/docs/releases/4.1.3.md @@ -23,3 +23,7 @@ depth: 1 * Fix timezone activation leaking into subsequent requests in `require_admin_access()` (Stefan Hammer) * Prevent matches from unrelated models from leaking into SQLite FTS searches (Matt Westcott) * Update Algolia DocSearch to use new application and correct versioning setup (Thibaud Colas) + +### Documentation + + * Docs: Clarify `ClusterableModel` requirements for using relations with `RevisionMixin`-enabled models (Sage Abdullah) diff --git a/docs/releases/4.2.1.md b/docs/releases/4.2.1.md index 91a11fa0ff..a517198fd9 100644 --- a/docs/releases/4.2.1.md +++ b/docs/releases/4.2.1.md @@ -24,3 +24,7 @@ depth: 1 * Prevent matches from unrelated models from leaking into SQLite FTS searches (Matt Westcott) * Prevent duplicate addition of StreamField blocks with the new block picker (Deepam Priyadarshi) * Update Algolia DocSearch to use new application and correct versioning setup (Thibaud Colas) + +### Documentation + + * Docs: Clarify `ClusterableModel` requirements for using relations with `RevisionMixin`-enabled models (Sage Abdullah) diff --git a/docs/releases/5.0.md b/docs/releases/5.0.md index 2218d0ef90..aa7fffc623 100644 --- a/docs/releases/5.0.md +++ b/docs/releases/5.0.md @@ -68,6 +68,7 @@ Support for adding custom validation logic to StreamField blocks has been formal * Remove confusing `SettingsPanel` reference in the page editing `TabbedInterface` example as `SettingsPanel` no longer shows anything as of 4.1 (Kenny Wolf, Julian Bigler) * Add contributor guidelines for building [Stimulus Controllers](ui_guidelines_stimulus) (Thibaud Colas, Loveth Omokaro, LB (Ben) Johnston) * Fix typo in "Extending Draftail" documentation (Hans Kelson) + * Docs: Clarify `ClusterableModel` requirements for using relations with `RevisionMixin`-enabled models (Sage Abdullah) ### Maintenance diff --git a/docs/topics/snippets.md b/docs/topics/snippets.md index 2fdf564267..103d011a40 100644 --- a/docs/topics/snippets.md +++ b/docs/topics/snippets.md @@ -274,8 +274,7 @@ class Advert(index.Indexed, models.Model): ## Saving revisions of snippets -If a snippet model inherits from {class}`~wagtail.models.RevisionMixin`, Wagtail will automatically save revisions when you save any changes in the snippets admin. -In addition to inheriting the mixin, it is recommended to define a {class}`~django.contrib.contenttypes.fields.GenericRelation` to the {class}`~wagtail.models.Revision` model and override the {attr}`~wagtail.models.RevisionMixin.revisions` property to return the `GenericRelation`. For example, the `Advert` snippet could be made revisable as follows: +If a snippet model inherits from {class}`~wagtail.models.RevisionMixin`, Wagtail will automatically save revisions when you save any changes in the snippets admin. In addition to inheriting the mixin, it is recommended to define a {class}`~django.contrib.contenttypes.fields.GenericRelation` to the {class}`~wagtail.models.Revision` model as the {attr}`~wagtail.models.RevisionMixin.revisions` attribute so that you can do related queries. If you need to customise how the revisions are fetched (e.g. to handle the content type to use for models with multi-table inheritance), you can define a property instead. For example, the `Advert` snippet could be made revisable as follows: ```python # ... @@ -289,6 +288,7 @@ from wagtail.models import RevisionMixin class Advert(RevisionMixin, models.Model): url = models.URLField(null=True, blank=True) text = models.CharField(max_length=255) + # If no custom logic is required, this can be defined as `revisions` directly _revisions = GenericRelation("wagtailcore.Revision", related_query_name="advert") panels = [ @@ -298,10 +298,11 @@ class Advert(RevisionMixin, models.Model): @property def revisions(self): + # Some custom logic here if necessary return self._revisions ``` -If your snippet model defines relations using Django's {class}`~django.db.models.ForeignKey` or {class}`~django.db.models.ManyToManyField`, you need to change the model class to inherit from `modelcluster.models.ClusterableModel` instead of `django.models.Model` and replace the `ForeignKey` and `ManyToManyField` with `ParentalKey` and `ParentalManyToManyField`, respectively. This is necessary in order to allow the relations to be stored in the revisions. For example: +If your snippet model defines relations using Django's {class}`~django.db.models.ManyToManyField`, you need to change the model class to inherit from `modelcluster.models.ClusterableModel` instead of `django.models.Model` and replace the `ManyToManyField` with `ParentalManyToManyField`. Inline models should continue to use `ParentalKey` instead of `ForeignKey`. This is necessary in order to allow the relations to be stored in the revisions. See the [](tutorial_categories) section of the tutorial for more details. For example: ```python from django.db import models @@ -325,19 +326,26 @@ class ShirtCategory(models.Model): @register_snippet class Shirt(RevisionMixin, ClusterableModel): name = models.CharField(max_length=255) - colour = ParentalKey("shirts.ShirtColour") + colour = models.ForeignKey("shirts.ShirtColour", on_delete=models.SET_NULL, blank=True, null=True) categories = ParentalManyToManyField("shirts.ShirtCategory", blank=True) - _revisions = GenericRelation("wagtailcore.Revision", related_query_name="shirt") + revisions = GenericRelation("wagtailcore.Revision", related_query_name="shirt") panels = [ FieldPanel("name"), FieldPanel("colour"), FieldPanel("categories", widget=forms.CheckboxSelectMultiple), + InlinePanel("images", label="Images"), ] - @property - def revisions(self): - return self._revisions + +class ShirtImage(models.Model): + shirt = ParentalKey("shirts.Shirt", related_name="images") + image = models.ForeignKey("wagtailimages.Image", on_delete=models.CASCADE, related_name="+") + caption = models.CharField(max_length=255, blank=True) + panels = [ + FieldPanel("image"), + FieldPanel("caption"), + ] ``` The `RevisionMixin` includes a `latest_revision` field that needs to be added to your database table. Make sure to run the `makemigrations` and `migrate` management commands after making the above changes to apply the changes to your database.