From 693878644498d459ef1b97439635640aef85a68e Mon Sep 17 00:00:00 2001 From: Matt Westcott Date: Wed, 12 Mar 2025 15:27:01 +0000 Subject: [PATCH] Ignore min_num constraints when deferring validation --- wagtail/blocks/stream_block.py | 17 +++++----- wagtail/tests/test_streamfield.py | 53 +++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/wagtail/blocks/stream_block.py b/wagtail/blocks/stream_block.py index 343754b76d..a3d0c4c00f 100644 --- a/wagtail/blocks/stream_block.py +++ b/wagtail/blocks/stream_block.py @@ -172,15 +172,16 @@ class BaseStreamBlock(Block): except ValidationError as e: errors[i] = e - if self.meta.min_num is not None and self.meta.min_num > len(value): - non_block_errors.append( - ValidationError( - _("The minimum number of items is %(min_num)d") - % {"min_num": self.meta.min_num} + if self.required and not ignore_required_constraints: + if self.meta.min_num is not None and self.meta.min_num > len(value): + non_block_errors.append( + ValidationError( + _("The minimum number of items is %(min_num)d") + % {"min_num": self.meta.min_num} + ) ) - ) - elif self.required and not ignore_required_constraints and len(value) == 0: - non_block_errors.append(ValidationError(_("This field is required."))) + elif len(value) == 0: + non_block_errors.append(ValidationError(_("This field is required."))) if self.meta.max_num is not None and self.meta.max_num < len(value): non_block_errors.append( diff --git a/wagtail/tests/test_streamfield.py b/wagtail/tests/test_streamfield.py index e68511d76c..534382f085 100644 --- a/wagtail/tests/test_streamfield.py +++ b/wagtail/tests/test_streamfield.py @@ -8,6 +8,7 @@ from django.test import TestCase, skipUnlessDBFeature from django.utils.safestring import SafeString from wagtail import blocks +from wagtail.admin.forms import WagtailAdminModelForm from wagtail.blocks import StreamBlockValidationError, StreamValue from wagtail.fields import StreamField from wagtail.images.models import Image @@ -22,6 +23,7 @@ from wagtail.test.testapp.models import ( JSONStreamModel, StreamPage, ) +from wagtail.test.utils.form_data import nested_form_data, streamfield class TestLazyStreamField(TestCase): @@ -547,6 +549,57 @@ class TestStreamFieldCountValidation(TestCase): instance = JSONMinMaxCountStreamModel.objects.create(body=json.dumps(body)) self.assertTrue(instance.body.stream_block.clean(instance.body)) + def test_minimum_count_disregarded_when_deferring_validation(self): + class StreamForm(WagtailAdminModelForm): + class Meta: + model = JSONMinMaxCountStreamModel + fields = ["body"] + defer_required_on_fields = ["body"] + + form_data = nested_form_data( + { + "body": streamfield( + [ + ("text", "Some text"), + ] + ) + } + ) + form = StreamForm(form_data) + self.assertFalse(form.is_valid()) + + form = StreamForm(form_data) + # form.defer_required_fields() + # self.assertTrue(form.is_valid()) + + def test_maximum_count_respected_when_deferring_validation(self): + class StreamForm(WagtailAdminModelForm): + class Meta: + model = JSONMinMaxCountStreamModel + fields = ["body"] + defer_required_on_fields = ["body"] + + form_data = nested_form_data( + { + "body": streamfield( + [ + ("text", "Some text"), + ("text", "Some text"), + ("text", "Some text"), + ("text", "Some text"), + ("text", "Some text"), + ("text", "Some text"), + ] + ) + } + ) + form = StreamForm(form_data) + self.assertFalse(form.is_valid()) + + form = StreamForm(form_data) + # form.defer_required_fields() + self.assertFalse(form.is_valid()) + def test_maximum_count(self): # 5 blocks okay body = [self.rich_text_body] * 5