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.

Validation errors applied to ListBlocks inside StructBlocks don't get rendered.

See original GitHub issue

I’ve got a custom clean() method on my StructBlock subclass, TestBlock. TestBlock contains two child blocks: text_field (a CharBlock) and list_field (a ListBlock of CharBlocks). My custom clean() method ensures that the user provides at least three elements to list_field, otherwise it throws a ValidationError. Here’s the code:

class TestBlock(blocks.StructBlock):

    text_field = blocks.CharBlock(
        label='Text',
        max_length=255
    )
    list_field = blocks.ListBlock(
        blocks.CharBlock(max_length=255),
        default=[],
    )

    class Meta:
        label = 'Test Block'
        template = 'app/blocks/TestBlock.html'
        form_classname = 'test-block struct-block'

    def clean(self, value):
        result = super().clean(value)
        errors = {}
        list_field_count = len(value['list_field'])
        if list_field_count < 3:
            errors['list_field'] = ErrorList(['You must provide at least three.'])
        if errors:
            # The message here is arbitrary - StructBlock.render_form will suppress it
            # and delegate the errors contained in the 'params' dict to the child blocks
            raise ValidationError('TableBlock received invalid data', params=errors)
        return result

The problem is that while the validator will successfully mark the form with an error if the user provides less than 3 elements for list_field, the form will not render the “You must provide at least three” message anywhere. Here’s a screenshot of what I mean: Screen Shot 2019-05-15 at 3 34 56 PM

However, by changing errors['list_field'] to errors['text_field'] in the clean() method, you get this: Screen Shot 2019-05-15 at 3 40 39 PM

So the error rendering is functioning properly on CharBlock. It’s just not working on ListBlock, for some reason.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
bmoe872commented, Nov 19, 2019

@loicteixeira I’m running into this same problem, and I do think this is a bug.

With the explanation that was given, I don’t see how it’s not a bug. The code snippet you provided is the clean method for the ListBlock, but the original problem is the override of the clean method on the StructBlock specifically, wherein overriding this should apply the appropriate error to the list block itself, and not “Within” the list block.

Further, even if the ListBlock has a different definition for Clean, then it should behave the same as other fields within a StructBlock no? i.e. the clean definition on ListBlock should not interfere with the StructBlock’s clean method.

0reactions
gasmancommented, Nov 19, 2019

I agree with @loicteixeira’s assessment. Validation error handling on StreamField blocks works on the contract that whenever a block’s clean method throws an exception, that same exception object will ultimately be passed back to that block’s render_form method to be rendered back to the user.

Since the top-level StreamField’s clean method can only throw one exception back to Django’s forms framework - even if there are multiple errors within it - any block that acts as a container for child blocks (such as StructBlock and ListBlock) is responsible for bundling up the exceptions thrown by its children into a single ValidationError, and then unbundling them again in render_form to pass each of those exceptions back to the relevant child’s render_form method.

It’s important to note that this “bundling” mechanism is private to each container block type, and any ValidationError objects emerging from it should be treated as a “black box” - they are liable to contain a specially-crafted params dict that is only understood by that one block.

The line errors['list_field'] = ErrorList(['You must provide at least three.']) is breaking this contract - it’s constructing a ValidationError that will ultimately be pushed to ListBlock.render_form but doesn’t follow ListBlock’s internal format for ValidationErrors.

The piece that’s really missing here is that ListBlock currently has no concept of “non field errors” - it assumes that any validation errors are the responsibility of one of its child blocks. Once you implement that, then you’re 90% of the way towards supporting min_num / max_num arguments on ListBlock, which I suspect is the feature you’re really looking for here 😃 And, indeed, one of the things #3914 implements is a ValidationError subclass with provision for non-block errors, to match the one that already exists for StreamBlock.

(I’m half inclined to close this as a duplicate of #2379 - but on the other hand #3914 is largely blocked by the Javascript code, which would be part of a complete min_num / max_num solution but out of the scope of what’s being discussed here - so I think we can consider the server-side validation to be a useful stepping stone. In other words: adding server-side validation for min_num / max_num on ListBlock will close this ticket, and adding the corresponding constraints on the client-side UI will close #2379.)

Read more comments on GitHub >

github_iconTop Results From Across the Web

Freeform page content using StreamField
A block which doesn't have any fields, thus passes no particular values to its template during rendering. This can be useful if you...
Read more >
Validation layers - Vulkan Tutorial
Validation layers are optional components that hook into Vulkan function calls to apply additional operations. Common operations in validation layers are:.
Read more >
Exception & Error Handling in Absinthe - Sheharyar Naseer
Set up a mechanism to automatically render these errors in the correct format in both Phoenix controllers and Absinthe resolvers; Gracefully ...
Read more >
Real-Time Form Validation with Phoenix LiveView
In this post, I'll show you how to build LiveView forms that validate changes and provide feedback to the user in real-time. Along...
Read more >
Configuration Blocks and Attributes - Terragrunt
Blocks. terraform; remote_state; include; locals; dependency; dependencies; generate. terraform. The terraform block is used to configure ...
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