mirror of
https://github.com/wagtail/wagtail.git
synced 2024-12-01 11:41:20 +01:00
Add ability to specify min/max block counts on StreamBlock
This commit is contained in:
parent
14a36f29c0
commit
58ad6545be
@ -441,9 +441,18 @@ Since ``StreamField`` accepts an instance of ``StreamBlock`` as a parameter, in
|
||||
.. code-block:: python
|
||||
|
||||
class HomePage(Page):
|
||||
carousel = StreamField(CarouselBlock())
|
||||
carousel = StreamField(CarouselBlock(max_num=10))
|
||||
|
||||
``StreamBlock`` accepts ``required`` as a keyword argument or ``Meta`` property; if true (the default), at least one sub-block must be supplied.
|
||||
``StreamBlock`` accepts the following options as either keyword arguments or ``Meta`` properties:
|
||||
|
||||
``required`` (default: True)
|
||||
If true, at least one sub-block must be supplied.
|
||||
|
||||
``min_num``
|
||||
Minimum number of sub-blocks that the stream must have.
|
||||
|
||||
``max_num``
|
||||
Maximum number of sub-blocks that the stream may have.
|
||||
|
||||
|
||||
.. _streamfield_personblock_example:
|
||||
|
@ -13,6 +13,7 @@ from django.utils import six
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.html import format_html_join
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from wagtail.wagtailcore.utils import escape_script
|
||||
|
||||
@ -35,9 +36,13 @@ class StreamBlockValidationError(ValidationError):
|
||||
|
||||
class BaseStreamBlock(Block):
|
||||
|
||||
def __init__(self, local_blocks=None, **kwargs):
|
||||
def __init__(self, local_blocks=None, min_num=None, max_num=None, **kwargs):
|
||||
self._constructor_kwargs = kwargs
|
||||
|
||||
# Used to validate the minimum and maximum number of elements in the block
|
||||
self.min_num = min_num
|
||||
self.max_num = max_num
|
||||
|
||||
super(BaseStreamBlock, self).__init__(**kwargs)
|
||||
|
||||
# create a local (shallow) copy of base_blocks so that it can be supplemented by local_blocks
|
||||
@ -196,6 +201,17 @@ class BaseStreamBlock(Block):
|
||||
if self.required and len(value) == 0:
|
||||
non_block_errors.append(ValidationError('This field is required', code='invalid'))
|
||||
|
||||
# Validate that the min_num and max_num has a value
|
||||
# and if it does meet the conditions of the number of components in the block
|
||||
if self.min_num and self.min_num > len(value):
|
||||
non_block_errors.append(ErrorList(
|
||||
[_('The minimum number of items is %s' % self.min_num)]
|
||||
))
|
||||
if self.max_num and self.max_num < len(value):
|
||||
non_block_errors.append(ErrorList(
|
||||
[_('The maximum number of items is %s' % self.max_num)]
|
||||
))
|
||||
|
||||
if errors or non_block_errors:
|
||||
# The message here is arbitrary - outputting error messages is delegated to the child blocks,
|
||||
# which only involves the 'params' list
|
||||
|
@ -2040,6 +2040,39 @@ class TestStreamBlock(WagtailTestUtils, SimpleTestCase):
|
||||
3: ['Enter a valid URL.'],
|
||||
})
|
||||
|
||||
def test_min_num_validation_errors(self):
|
||||
class ValidatedBlock(blocks.StreamBlock):
|
||||
char = blocks.CharBlock()
|
||||
url = blocks.URLBlock()
|
||||
block = ValidatedBlock(min_num=1)
|
||||
|
||||
value = blocks.StreamValue(block, [])
|
||||
|
||||
with self.assertRaises(ValidationError) as catcher:
|
||||
block.clean(value)
|
||||
self.assertEqual(catcher.exception.params, {
|
||||
'__all__': [['The minimum number of items is 1']]
|
||||
})
|
||||
|
||||
def test_max_num_validation_errors(self):
|
||||
class ValidatedBlock(blocks.StreamBlock):
|
||||
char = blocks.CharBlock()
|
||||
url = blocks.URLBlock()
|
||||
block = ValidatedBlock(max_num=1)
|
||||
|
||||
value = blocks.StreamValue(block, [
|
||||
('char', 'foo'),
|
||||
('char', 'foo'),
|
||||
('url', 'http://example.com/'),
|
||||
('url', 'http://example.com/'),
|
||||
])
|
||||
|
||||
with self.assertRaises(ValidationError) as catcher:
|
||||
block.clean(value)
|
||||
self.assertEqual(catcher.exception.params, {
|
||||
'__all__': [['The maximum number of items is 1']]
|
||||
})
|
||||
|
||||
def test_block_level_validation_renders_errors(self):
|
||||
block = FooStreamBlock()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user