question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

StreamField and StreamBlock have confusing behaviour with `required` and `blank` properties

See original GitHub issue

Issue 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 the StreamBlock as the top-level block of a StreamField; in this case the StreamField’s blank 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 is
  • nonrequired should not be required*, and it is not (you can submit an empty field), but the red ‘required’ asterisk is shown
  • blank should be not required (in this case the StreamField’s blank property is respected instead), and yet it is, although the red ‘required’ asterisk is not shown
  • nonrequired_blank should produce a blank block, but allegedly specifying required=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:closed
  • Created 6 years ago
  • Reactions:4
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

7reactions
alexgleasoncommented, Aug 29, 2018

@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-required

I disagree that this is confusing behavior; it’s a bug. Here’s my reasoning:

  • StreamField is a normal Django model field, just like CharField, TextField, etc.
  • When a Django model field has blank=True, it validates even when the field is empty.
  • A StreamField is empty when it contains no blocks.

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 with required=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.

2reactions
coredumperrorcommented, Apr 24, 2018

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:

    assets = StreamField(
        MixedMediaCarouselBlock(),
        help_text='Pick one or more images/videos to place in the sidebar of this article.',
        blank=True
    )

Adding required=False as an argument to MixedMediaCarouselBlock() (which derives from StreamBlock) 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.

Read more comments on GitHub >

github_iconTop Results From Across the Web

StreamField block reference - Wagtail's documentation
This is ignored when using the StreamBlock as the top-level block of a StreamField; in this case the StreamField's blank property is respected...
Read more >
Release 2.2.2 Torchbox - Wagtail Documentation
cluding the required project settings, a “home” app with a blank ... field, though StreamField fields need to use a specialised panel class....
Read more >
django-streamfield-w - PyPI
Model-field attributes. Are the same as any model field, 'blank', 'help_text', 'verbose_name', 'validators' etc. Consider that the ...
Read more >
Top-level StreamBlock within StreamField doesn't render in ...
images.blocks import ImageChooserBlock class HeroButtonBlock(blocks.StructBlock): button_text = blocks.CharBlock(required=False) button_page = ...
Read more >
CHANGELOG.txt - GitHub
... are visible on screen (Jake Howard) * Allow setting default attributes on ... StreamField required status is now consistently handled by the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found