Fix - Ensure `WagtailAdminFormPageForm.clean` works for any related name

Dynamically detect the `related_name` of any form fields attached to the page so that validation is actually run for custom related_names.

This also will apply validation even if there are multiple `AbstractFormField` subclasses related to the page.

Add unit test to ensure that duplicate clean name validation correctly runs on FormPage models with a custom related name.

Originally from #10375
pull/12536/head
LB 2024-10-29 06:40:24 +10:00 zatwierdzone przez Matt Westcott
rodzic 9d31fd3fa5
commit 281efdbc88
2 zmienionych plików z 69 dodań i 6 usunięć

Wyświetl plik

@ -173,17 +173,34 @@ class SelectDateForm(django.forms.Form):
class WagtailAdminFormPageForm(WagtailAdminPageForm):
def clean(self):
cleaned_data = super().clean()
related_name = "form_fields"
"""
Dynamically detect all related AbstractFormField subclasses to ensure
validation is applied regardless of the related_name or if there are multiple
AbstractFormField subclasses related to this page.
"""
from .models import AbstractFormField
cleaned_data = super().clean()
form_fields_related_names = [
related_object.related_name
for related_object in self.instance._meta.related_objects
if issubclass(related_object.related_model, AbstractFormField)
]
for related_name in form_fields_related_names:
if related_name not in self.formsets:
continue
# Check for duplicate form fields by comparing their internal clean_names
if "form_fields" in self.formsets:
forms = self.formsets[related_name].forms
for form in forms:
form.is_valid()
# Use existing clean_name or generate for new fields.
# clean_name is set in FormField.save
# Use existing clean_name or generate for new fields,
# raise an error if there are duplicate resolved clean names.
# Note: `clean_name` is set in `FormField.save`.
clean_names = [
f.instance.clean_name or f.instance.get_field_clean_name()
for f in forms

Wyświetl plik

@ -1973,6 +1973,52 @@ class TestDuplicateFormFieldLabels(WagtailTestUtils, TestCase):
text="There is another field with the label Test field, please change one of them.",
)
def test_adding_duplicate_form_labels_with_custom_related_name(self):
"""
Ensure duplicate field names are checked, even if a custom related_name is used.
``FormPageWithCustomSubmission`` uses the related_name `custom_form_fields`.
"""
post_data = {
"title": "Drink selection",
"content": "Some content",
"slug": "drink-selection",
"custom_form_fields-TOTAL_FORMS": "3",
"custom_form_fields-INITIAL_FORMS": "3",
"custom_form_fields-MIN_NUM_FORMS": "0",
"custom_form_fields-MAX_NUM_FORMS": "1000",
# Duplicate field labels
"custom_form_fields-0-id": "",
"custom_form_fields-0-label": "chocolate",
"custom_form_fields-0-field_type": "singleline",
"custom_form_fields-1-id": "",
"custom_form_fields-1-label": "chocolate",
"custom_form_fields-1-field_type": "singleline",
# Unique field label
"custom_form_fields-2-id": "",
"custom_form_fields-2-label": "coffee",
"custom_form_fields-2-field_type": "singleline",
}
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,
text="There is another field with the label chocolate, please change one of them.",
)
class TestPreview(WagtailTestUtils, TestCase):
post_data = {