diff --git a/wagtail/admin/panels/field_panel.py b/wagtail/admin/panels/field_panel.py index 4b446230c8..02f07b2fcf 100644 --- a/wagtail/admin/panels/field_panel.py +++ b/wagtail/admin/panels/field_panel.py @@ -67,7 +67,10 @@ class FieldPanel(Panel): except FieldDoesNotExist: required_on_save = False else: - required_on_save = getattr(db_field, "required_on_save", False) + required_on_save = getattr(db_field, "required_on_save", False) or ( + db_field.null is False + and db_field.get_internal_type() not in ("CharField", "TextField") + ) if not required_on_save: opts["defer_required_on_fields"] = [self.field_name] diff --git a/wagtail/admin/tests/pages/test_create_page.py b/wagtail/admin/tests/pages/test_create_page.py index 283369dfbd..0f02384c49 100644 --- a/wagtail/admin/tests/pages/test_create_page.py +++ b/wagtail/admin/tests/pages/test_create_page.py @@ -672,6 +672,37 @@ class TestPageCreation(WagtailTestUtils, TestCase): ).exists() ) + def test_cannot_create_page_with_blank_required_date(self): + """ + A non-nullable, non-text field cannot be saved with a blank value, so we should + enforce requiredness even when saving as draft + """ + post_data = { + "title": "Page with missing date", + "deadline": "", + "slug": "missing-date", + } + response = self.client.post( + reverse( + "wagtailadmin_pages:add", + args=("tests", "requireddatepage", self.root_page.id), + ), + post_data, + ) + self.assertEqual(response.status_code, 200) + + # Check that a form error was raised + self.assertFormError( + response.context["form"], "deadline", "This field is required." + ) + + # Page should not have been created + self.assertFalse( + Page.objects.filter( + path__startswith=self.root_page.path, slug="missing-date" + ).exists() + ) + def test_create_simplepage_scheduled(self): go_live_at = timezone.now() + datetime.timedelta(days=1) expire_at = timezone.now() + datetime.timedelta(days=2) diff --git a/wagtail/test/testapp/migrations/0048_requireddatepage.py b/wagtail/test/testapp/migrations/0048_requireddatepage.py new file mode 100644 index 0000000000..85add7c08e --- /dev/null +++ b/wagtail/test/testapp/migrations/0048_requireddatepage.py @@ -0,0 +1,36 @@ +# Generated by Django 5.1.5 on 2025-02-28 00:28 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("tests", "0047_advertwithcustomuuidprimarykey_page"), + ("wagtailcore", "0094_alter_page_locale"), + ] + + operations = [ + migrations.CreateModel( + name="RequiredDatePage", + fields=[ + ( + "page_ptr", + models.OneToOneField( + auto_created=True, + on_delete=django.db.models.deletion.CASCADE, + parent_link=True, + primary_key=True, + serialize=False, + to="wagtailcore.page", + ), + ), + ("deadline", models.DateField()), + ], + options={ + "abstract": False, + }, + bases=("wagtailcore.page",), + ), + ] diff --git a/wagtail/test/testapp/models.py b/wagtail/test/testapp/models.py index 778c0747e1..03a227a423 100644 --- a/wagtail/test/testapp/models.py +++ b/wagtail/test/testapp/models.py @@ -2487,3 +2487,12 @@ class CustomPermissionModel(models.Model): register_snippet(CustomPermissionModel) + + +class RequiredDatePage(Page): + deadline = models.DateField() + + content_panels = [ + TitleFieldPanel("title", classname="title"), + FieldPanel("deadline"), + ]