StreamField and StreamBlock have confusing behaviour with `required` and `blank` properties
See original GitHub issueIssue Summary
The documentation doesn’t correspond to the actual behaviour of an optional top-level StreamBlock, and in some circumstances the behaviour is confusing even without the conflicting documentation.
From http://docs.wagtail.io/en/v1.13.1/topics/streamfield.html#streamblock:
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. This is ignored when using theStreamBlock
as the top-level block of a StreamField; in this case the StreamField’sblank
property is respected instead.
In fact, setting required=False
in the StreamBlock and blank=True
on the StreamField are both necessary to produce an optional field that also looks optional.
Steps to Reproduce
Configure the following models.py:
from wagtail.wagtailadmin.edit_handlers import StreamFieldPanel
from wagtail.wagtailcore.blocks import StreamBlock, TextBlock
from wagtail.wagtailcore.models import Page
from wagtail.wagtailcore.fields import StreamField
class TestModel(Page):
basic = StreamField(StreamBlock([('text', TextBlock())]))
nonrequired = StreamField(StreamBlock([('text', TextBlock())], required=False))
blank = StreamField(StreamBlock([('text', TextBlock())]), blank=True)
nonrequired_blank = StreamField(StreamBlock([('text', TextBlock())], required=False), blank=True)
content_panels = Page.content_panels + [
StreamFieldPanel('basic'),
StreamFieldPanel('nonrequired'),
StreamFieldPanel('blank'),
StreamFieldPanel('nonrequired_blank'),
]
Based on the documentation…
basic
should be a required field, which it isnonrequired
should not be required*, and it is not (you can submit an empty field), but the red ‘required’ asterisk is shownblank
should be not required (in this case the StreamField’sblank
property is respected instead), and yet it is, although the red ‘required’ asterisk is not shownnonrequired_blank
should produce a blank block, but allegedly specifyingrequired=False
is superfluous, however this is the only way to get a non-required block that also looks optional to site editors.
* though you’d think that a field with blank=False
implicitly set would fail validation
Technical details
- Wagtail version: 1.13.1
Issue Analytics
- State:
- Created 6 years ago
- Reactions:4
- Comments:6 (3 by maintainers)
Top GitHub Comments
@coredumperror’s workaround fixed it for me. Just pass
required=False
into the StreamBlock. Thank you!I see this is tagged
some-day
. If this is a complicated issue to fix, I think noting the issue in the docs might be worth it. There’s a StackOverflow question about it which points to the docs, which aren’t correct: https://stackoverflow.com/questions/47336893/how-can-i-make-a-wagtail-streamfield-not-requiredI disagree that this is confusing behavior; it’s a bug. Here’s my reasoning:
blank=True
, it validates even when the field is empty.Therefore, when a SteamField is empty (ie containing no blocks) and has
blank=True
, the form should validate. It doesn’t matter if the StreamField could contain blocks withrequired=True
.If the StreamField does have blocks added to it, and those blocks are blank with
required=True
, then the form should invalidate on those specific blocks.A StreamField should only be invalid if
blank=False
and the StreamField contains no blocks. The state of the child blocks shouldn’t matter to StreamField. All that matters is whether blocks exist or not.I’m suffering from this same problem. The following code results in a SteamBlock that doesn’t have a little red asterisk in the form to indicate “required”, but still throws an error of “This field is required” when you try to save it with no blocks:
Adding
required=False
as an argument toMixedMediaCarouselBlock()
(which derives fromStreamBlock
) is the only way to make it possible to submit the form with no blocks in the field.I am also using Wagtail 1.13.1.