Wagtail's Silent Errors: Why ValidationErrors Go Missing and How to Fix Them
Wagtail, a powerful content management system built on Django, provides excellent tools for building beautiful websites. However, one common frustration users encounter is the lack of clear error messages during form validation. While Wagtail excels at handling user-facing input, its approach to displaying ValidationError
instances can lead to confusion.
The Problem:
Imagine you're working on a Wagtail page that requires a specific format for a phone number field. You've set up validation in your Django model, but when a user enters an incorrect number, you see nothing but a generic "Please correct the errors below." This lack of clarity makes debugging and user feedback challenging.
Scenario and Code:
Let's say you have a ContactPage
model in your Wagtail project:
from wagtail.core.models import Page
from wagtail.admin.edit_handlers import FieldPanel
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
class ContactPage(Page):
phone_number = models.CharField(max_length=20, blank=True)
def clean(self):
cleaned_data = super().clean()
phone_number = cleaned_data.get('phone_number')
# Simple phone number validation (you might want to use a more robust library)
if phone_number and not phone_number.isdigit():
raise ValidationError(_("Please enter a valid phone number consisting only of digits."), code='invalid_phone')
return cleaned_data
panels = [
FieldPanel('title'),
FieldPanel('phone_number'),
]
In this example, if a user enters a phone number with letters, they'll get the generic error message, but not the specific "Please enter a valid phone number consisting only of digits" message.
Why is this happening?
The issue stems from how Wagtail handles form submissions. It relies on Django's built-in form handling, but it uses a custom form class (WagtailAdminPageForm
) that overrides the default error handling behavior. This leads to:
- Limited error display: By default, only the error codes ("invalid_phone" in our example) are presented to the user.
- Missing custom messages: The specific error messages you define in
ValidationError
are not displayed on the page.
Solutions:
-
Explicit Error Handling: You can customize the error rendering by overriding
WagtailAdminPageForm
and implementing your own error handling logic:from wagtail.admin.forms import WagtailAdminPageForm from django.forms.utils import ErrorList class ContactPageForm(WagtailAdminPageForm): def clean(self): cleaned_data = super().clean() phone_number = cleaned_data.get('phone_number') # ... your phone number validation ... return cleaned_data def get_errors(self): errors = super().get_errors() for field_name, field_errors in errors.items(): if 'invalid_phone' in field_errors.codes: error_message = _('Please enter a valid phone number consisting only of digits.') errors[field_name] = ErrorList([error_message]) return errors
-
Wagtail 2.15+: Custom Error Messages: In recent Wagtail versions, the
WagtailAdminPageForm
was improved. You can now define custom error messages directly within theValidationError
:from wagtail.core.models import Page from wagtail.admin.edit_handlers import FieldPanel from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ class ContactPage(Page): # ... your model fields ... def clean(self): cleaned_data = super().clean() phone_number = cleaned_data.get('phone_number') if phone_number and not phone_number.isdigit(): raise ValidationError( _("Please enter a valid phone number consisting only of digits."), code='invalid_phone' ) return cleaned_data panels = [ # ... your panels ... ]
Key Takeaways:
- Wagtail's default error handling might not always display
ValidationError
messages as expected. - You can customize error handling by overriding the form class or utilizing the latest Wagtail features.
- Be specific with your error messages to provide clear feedback to users and facilitate better debugging.
Additional Resources: