Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to perform validation on related Orderable in InlinePanel in WagtailCMS?

I am using Wagtail CMS and I need some validation for my Orderable model. Like, ensuring that at most one of the fields is filled.

Normally, I would override the clean(self) method for the Django model, but calling super().clean() inside that method returns None. I am still able to access the fields with self.field_name and raising ValidationError still prevents the model from creation, but it doesn't show which fields caused the error for the model in the admin interface.

I have tried overriding the clean method, that stops the model from being committed but doesn't show errors on the interface

I have tried following this part of the guide, but the clean method there isn't even called for the Orderable.

This is the example of my clean method

def clean(self):
    super().clean()
    has_image =  self.image is not None
    has_video = self.video_url is not None

    if has_image == has_video:
        raise ValidationError('Either a video or an image must be set')

I expect validation errors to show up in the admin interface.

like image 308
Ilya Borovitinov Avatar asked Jan 25 '26 03:01

Ilya Borovitinov


1 Answers

I've dug into the wagtail source code and I think I found the way of how to access the form controls for the orderable.

Let's say you have a model for a page,

class TestPage(Page):

    testPageTitle = RichTextField(blank=True, max_length=250)

    content_panels = Page.content_panels + [
    FieldPanel('testPageTitle'),
    InlinePanel('test_page_field')
    ]

    base_form_class = TestPageForm

with some orderable model, that is linked to the page through a related name 'test_page_field',

class TestPageField(Orderable):
    page = ParentalKey(TestPage, on_delete=models.CASCADE, related_name='test_page_field')

    testPageFieldTitle = models.CharField(blank=True, max_length=250)

    panels = [
    FieldPanel('testPageFieldFieldTitle')
    ]

then you can access that within the clean method of the page, via self.formsets['test_page_field'].forms, which is a list of Django form objects, where the regular checks can be done and .add_error() method can be used. The relevant base_form_class would look as follows:

class TestPageForm(WagtailAdminPageForm):

    def clean(self):
    cleaned_data = super().clean()

    #loop over linked orderables
    for form in self.formsets['test_page_field'].forms:

        #check first if form is valid, otherwise cleaned_data will not be accesible/set
        if form.is_valid():
            cleaned_form_data = form.clean()
            testPageFieldFieldTitle = cleaned_form_data.get('testPageFieldFieldTitle')

            #execute some validation condition, and raise the error if it fails
            if testPageFieldFieldTitle is None:
                form.add_error('testPageFieldFieldTitle', 'please dont leave me empty')

    return cleaned_data

I hope this helps.

like image 128
user59271 Avatar answered Jan 26 '26 15:01

user59271



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!