diff --git a/wagtail/signal_handlers.py b/wagtail/signal_handlers.py index 8431843f5f..1695c67f10 100644 --- a/wagtail/signal_handlers.py +++ b/wagtail/signal_handlers.py @@ -83,6 +83,9 @@ def update_reference_index_on_save(instance, **kwargs): break instance = getattr(instance, parental_keys[0].name) + if instance is None: + # parent is null, so there is no valid object to record references against + return if ReferenceIndex.model_is_indexable(type(instance)): with transaction.atomic(): diff --git a/wagtail/test/testapp/migrations/0011_modelwithnullableparentalkey.py b/wagtail/test/testapp/migrations/0011_modelwithnullableparentalkey.py new file mode 100644 index 0000000000..1ad92ddd94 --- /dev/null +++ b/wagtail/test/testapp/migrations/0011_modelwithnullableparentalkey.py @@ -0,0 +1,41 @@ +# Generated by Django 4.1.2 on 2022-11-04 14:00 + +from django.db import migrations, models +import django.db.models.deletion +import modelcluster.fields +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ("wagtailcore", "0078_referenceindex"), + ("tests", "0010_alter_customimage_file_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="ModelWithNullableParentalKey", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("content", wagtail.fields.RichTextField()), + ( + "page", + modelcluster.fields.ParentalKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="wagtailcore.page", + ), + ), + ], + ), + ] diff --git a/wagtail/test/testapp/models.py b/wagtail/test/testapp/models.py index 33ee9b2017..1f243b3355 100644 --- a/wagtail/test/testapp/models.py +++ b/wagtail/test/testapp/models.py @@ -1975,3 +1975,14 @@ class ModelWithStringTypePrimaryKey(models.Model): custom_id = models.CharField(max_length=255, primary_key=True) content = models.CharField(max_length=255) + + +class ModelWithNullableParentalKey(models.Model): + """ + There's not really a valid use case for null parental keys, but their presence should not + break things outright (e.g. when determining the object ID to store things under in the + references index). + """ + + page = ParentalKey(Page, blank=True, null=True) + content = RichTextField() diff --git a/wagtail/tests/test_reference_index.py b/wagtail/tests/test_reference_index.py index 10c78e87c7..30089d0830 100644 --- a/wagtail/tests/test_reference_index.py +++ b/wagtail/tests/test_reference_index.py @@ -7,7 +7,11 @@ from django.test import TestCase from wagtail.images import get_image_model from wagtail.images.tests.utils import get_test_image_file from wagtail.models import Page, ReferenceIndex -from wagtail.test.testapp.models import EventPage, EventPageCarouselItem +from wagtail.test.testapp.models import ( + EventPage, + EventPageCarouselItem, + ModelWithNullableParentalKey, +) class TestCreateOrUpdateForObject(TestCase): @@ -163,6 +167,18 @@ class TestCreateOrUpdateForObject(TestCase): self.expected_references, ) + def test_null_parental_key(self): + obj = ModelWithNullableParentalKey( + content="""

event page

""" + % self.event_page.id + ) + obj.save() + + # Models with a ParentalKey are not considered indexable - references are recorded against the parent model + # instead. Since the ParentalKey is null here, no reference will be recorded. + refs = ReferenceIndex.get_references_to(self.event_page) + self.assertEqual(refs.count(), 0) + def test_rebuild_references_index_no_verbosity(self): stdout = StringIO() management.call_command(