Created
March 24, 2019 23:16
-
-
Save KalobTaulien/c1a6f2c9b356cadbd100d60d83d82bcb to your computer and use it in GitHub Desktop.
StructBlock StreamField Validation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.core.exceptions import ValidationError | |
from django.forms.utils import ErrorList | |
from wagtail.core import blocks | |
class CTABlock(blocks.StructBlock): | |
"""A simple call to action section.""" | |
button_url = blocks.URLBlock(required=False) | |
button_page = blocks.PageChooserBlock(required=False) | |
class Meta: # noqa | |
template = "streams/cta_block.html" | |
icon = "placeholder" | |
label = "Call to Action" | |
def clean(self, value): | |
# Error container | |
errors = {} | |
# Check if both fields are empty | |
if not value.get('button_url') and value.get('button_page') is None: | |
errors['button_url'] = ErrorList(['You must select a page, or enter a URL. Please fill just one of these.']) | |
errors['button_page'] = ErrorList(['You must select a page, or enter a URL. Please fill just one of these.']) | |
# Check if both fields are filled | |
elif value.get('button_url') and value.get('button_page'): | |
errors['button_url'] = ErrorList(['Please select a page OR enter a URL (choose one)']) | |
errors['button_page'] = ErrorList(['Please select a page OR enter a URL (choose one)']) | |
# If there are errors, raise a validation with the errors dict from line 20. | |
if errors: | |
raise ValidationError('Validation error in StructBlock', params=errors) | |
# If no ValidationError was raised, perform a regular clean on this StreaemField. | |
return super().clean(value) |
OK, I sorted it. In case you're curious about my approach, I simply took the StructBlock
out of the ListBlock
:
class DocumentItemBlock(StructBlock):
doc_name= CharBlock(label="Document name", required=False)
doc_file= DocumentChooserBlock(label="File to upload", required=False)
doc_alternative_url= URLBlock(label="Alternative link to the document", required=False)
def clean(self, value):
# This is for forcing the user to choose either an internal link or an external one,
# but not both.
# Error container
errors = {}
# Check if both fields are empty
if not value.get('doc_file') and value.get('doc_alternative_url') is "":
errors['doc_file'] = ErrorList(['You must select a page, or enter a URL. Please fill just one of these.'])
errors['doc_alternative_url'] = ErrorList(['You must select a page, or enter a URL. Please fill just one of these.'])
# Check if both fields are filled
elif value.get('doc_file') and value.get('doc_alternative_url'):
errors['doc_file'] = ErrorList(['Please select a page OR enter a URL (choose one)'])
errors['doc_alternative_url'] = ErrorList(['Please select a page OR enter a URL (choose one)'])
# If there are errors, raise a validation with the errors dict.
if any (errors):
raise ValidationError('Validation error in StructBlock', params=errors)
# If no ValidationError was raised, perform a regular clean on this StreamField.
return super().clean(value)
And then is just a matter of calling it from the other class:
class DocumentsBlock(StructBlock):
doc_category = CharBlock(label="Documents group")
document_item = ListBlock(
DocumentItemBlock(
label="Document description",
required=False)
)
Once again, thank you so much for your blog :D
For anyone who's errors are not showing at the field level, try changing your exception on line 33 to:
raise StructBlockValidationError(errors)
This is imported from:
from wagtail.core.blocks.struct_block import StructBlockValidationError
This comment outlines the reason for this. 🙂
Extending stevedya's answer, if someone is not able to import StructBlockValidationError
,
try importing from this
from wagtail.blocks.struct_block import StructBlockValidationError
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
As usual, a brilliant and clear tutorial. Thanks so much for it!
Also, it would be great if you can explain how to do something similar but with a
StructBlock
inside aListBlock
. It's something I have spent a lot of time and I still can't quite find how to do it. Something likeI tried with something like this:
But it's clearly not the way to do it... I can prevent the page from being saved, but I can't display the reason or indicate which fields are not correct...