kopia lustrzana https://github.com/wagtail/wagtail
Fix - Ensure `WagtailAdminFormPageForm.clean` returns `cleaned_data`
Return `cleaned_data` for more consistent subclassing. Updated documentation with an example of adding custom page validation for form fields. Add unit test to ensure that the documented usage of extending `WagtailAdminFormPageForm` works as expected. Originally from #10375pull/12536/head
rodzic
f600a356e6
commit
9d31fd3fa5
|
@ -825,3 +825,32 @@ class EmailFormPage(EmailFormMixin, FormMixin, BasePage):
|
|||
# ...
|
||||
|
||||
```
|
||||
|
||||
(form_builder_custom_admin_validation)=
|
||||
|
||||
## Custom validation for admin form pages
|
||||
|
||||
By default, pages that inherit from `FormMixin` will validate that each field added by an editor has a unique `clean_name`.
|
||||
|
||||
If you need to add custom validation, create a subclass of `WagtailAdminFormPageForm` and add your own `clean` definition and set the `base_form_class` on your `Page` model.
|
||||
|
||||
```{note}
|
||||
Validation only applies when editors use the form builder to add fields in the Wagtail admin,
|
||||
not when the form is submitted by end users.
|
||||
```
|
||||
|
||||
```python
|
||||
from wagtail.models import Page
|
||||
from wagtail.contrib.forms.models import FormMixin, WagtailAdminFormPageForm
|
||||
|
||||
|
||||
class CustomWagtailAdminFormPageForm(WagtailAdminFormPageForm):
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
# Insert custom validation here, see `WagtailAdminFormPageForm.clean` for an example
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class FormPage(AbstractForm):
|
||||
base_form_class = CustomWagtailAdminFormPageForm
|
||||
```
|
||||
|
|
|
@ -173,11 +173,12 @@ class SelectDateForm(django.forms.Form):
|
|||
|
||||
class WagtailAdminFormPageForm(WagtailAdminPageForm):
|
||||
def clean(self):
|
||||
super().clean()
|
||||
cleaned_data = super().clean()
|
||||
related_name = "form_fields"
|
||||
|
||||
# Check for duplicate form fields by comparing their internal clean_names
|
||||
if "form_fields" in self.formsets:
|
||||
forms = self.formsets["form_fields"].forms
|
||||
forms = self.formsets[related_name].forms
|
||||
for form in forms:
|
||||
form.is_valid()
|
||||
|
||||
|
@ -193,7 +194,7 @@ class WagtailAdminFormPageForm(WagtailAdminPageForm):
|
|||
if duplicate_clean_name:
|
||||
duplicate_form_field = next(
|
||||
f
|
||||
for f in self.formsets["form_fields"].forms
|
||||
for f in self.formsets[related_name].forms
|
||||
if f.instance.get_field_clean_name() == duplicate_clean_name
|
||||
)
|
||||
duplicate_form_field.add_error(
|
||||
|
@ -205,3 +206,5 @@ class WagtailAdminFormPageForm(WagtailAdminPageForm):
|
|||
% {"label_name": duplicate_form_field.instance.label}
|
||||
),
|
||||
)
|
||||
|
||||
return cleaned_data
|
||||
|
|
|
@ -2085,6 +2085,35 @@ class TestFormPageCreate(WagtailTestUtils, TestCase):
|
|||
response, reverse("wagtailadmin_pages:edit", args=(page.id,))
|
||||
)
|
||||
|
||||
def test_form_page_creation_error_with_custom_clean_method(self):
|
||||
"""
|
||||
CustomFormPageSubmission uses a custom `base_form_class` with a clean method
|
||||
that will raise a ValidationError if the from email contains 'example.com'.
|
||||
"""
|
||||
|
||||
post_data = {
|
||||
"title": "Drink selection",
|
||||
"slug": "drink-selection",
|
||||
"from_address": "bad@example.com",
|
||||
}
|
||||
|
||||
response = self.client.post(
|
||||
reverse(
|
||||
"wagtailadmin_pages:add",
|
||||
args=("tests", "formpagewithcustomsubmission", self.root_page.id),
|
||||
),
|
||||
post_data,
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
self.assertContains(
|
||||
response, "The page could not be created due to validation errors"
|
||||
)
|
||||
self.assertContains(
|
||||
response, "<li>Email cannot be from example.com</li>", count=1
|
||||
)
|
||||
|
||||
|
||||
class TestFormPageEdit(WagtailTestUtils, TestCase):
|
||||
def setUp(self):
|
||||
|
|
|
@ -44,7 +44,7 @@ from wagtail.blocks import (
|
|||
StreamBlock,
|
||||
StructBlock,
|
||||
)
|
||||
from wagtail.contrib.forms.forms import FormBuilder
|
||||
from wagtail.contrib.forms.forms import FormBuilder, WagtailAdminFormPageForm
|
||||
from wagtail.contrib.forms.models import (
|
||||
FORM_FIELD_CHOICES,
|
||||
AbstractEmailForm,
|
||||
|
@ -715,18 +715,37 @@ class FormPageWithRedirect(AbstractEmailForm):
|
|||
# FormPage with a custom FormSubmission
|
||||
|
||||
|
||||
class FormPageWithCustomSubmissionForm(WagtailAdminFormPageForm):
|
||||
"""
|
||||
Used to validate that admin forms can validate the page's submissions via
|
||||
extending the form class.
|
||||
"""
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
from_address = cleaned_data.get("from_address")
|
||||
if from_address and "example.com" in from_address:
|
||||
raise ValidationError("Email cannot be from example.com")
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class FormPageWithCustomSubmission(AbstractEmailForm):
|
||||
"""
|
||||
This Form page:
|
||||
* Have custom submission model
|
||||
* Have custom related_name (see `FormFieldWithCustomSubmission.page`)
|
||||
* Saves reference to a user
|
||||
* Doesn't render html form, if submission for current user is present
|
||||
A ``FormPage`` with a custom FormSubmission and other extensive customizations:
|
||||
|
||||
* A custom submission model
|
||||
* A custom related_name (see `FormFieldWithCustomSubmission.page`)
|
||||
* Saves reference to a user
|
||||
* Doesn't render html form, if submission for current user is present
|
||||
* A custom clean method that does not allow the ``from_address`` to be set to anything including example.com
|
||||
"""
|
||||
|
||||
intro = RichTextField(blank=True)
|
||||
thank_you_text = RichTextField(blank=True)
|
||||
|
||||
base_form_class = FormPageWithCustomSubmissionForm
|
||||
|
||||
def get_context(self, request, *args, **kwargs):
|
||||
context = super().get_context(request)
|
||||
context["greeting"] = "hello world"
|
||||
|
|
Ładowanie…
Reference in New Issue