diff --git a/django/contrib/admin/static/admin/css/forms.css b/django/contrib/admin/static/admin/css/forms.css index 6d13d433500e..6294f368b6f0 100644 --- a/django/contrib/admin/static/admin/css/forms.css +++ b/django/contrib/admin/static/admin/css/forms.css @@ -30,7 +30,8 @@ form .form-row p { flex-wrap: wrap; } -.form-multiline > div { +.form-multiline > div, +.form-multiline > fieldset { padding-bottom: 10px; } @@ -93,7 +94,7 @@ fieldset .inline-heading, /* ALIGNED FIELDSETS */ .aligned fieldset { - width: 100%; + flex-grow: 1; border-top: none; } diff --git a/docs/ref/csp.txt b/docs/ref/csp.txt index 5d0a9c0ecbd1..b5bf0c5f2e15 100644 --- a/docs/ref/csp.txt +++ b/docs/ref/csp.txt @@ -261,7 +261,7 @@ expression into the CSP header. To use this nonce in templates, the :func:`~django.template.context_processors.csp` context processor needs to be enabled. It adds a ``csp_nonce`` variable to the template context, allowing -inline elements to include a matching ``nonce={{ csp_nonce }}`` attribute in +inline elements to include a matching ``nonce="{{ csp_nonce }}"`` attribute in inline scripts or styles. The browser will only execute inline elements that include a ``nonce=`` diff --git a/docs/releases/6.0.2.txt b/docs/releases/6.0.2.txt index d74a8bd76345..7dd10dbb4e25 100644 --- a/docs/releases/6.0.2.txt +++ b/docs/releases/6.0.2.txt @@ -15,6 +15,9 @@ Bugfixes to wrap below the changelist when filter elements contained long text (:ticket:`36850`). +* Fixed a visual regression in Django 6.0 for admin form fields grouped under a + ``
`` aligned horizontally (:ticket:`36788`). + * Fixed a regression in Django 6.0 where ``auto_now_add`` field values were not populated during ``INSERT`` operations, due to incorrect parameters passed to ``field.pre_save()`` (:ticket:`36847`). diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py index 64e0e232290a..506f9d475dc2 100644 --- a/tests/admin_views/admin.py +++ b/tests/admin_views/admin.py @@ -1198,6 +1198,18 @@ class CamelCaseAdmin(admin.ModelAdmin): class CourseAdmin(admin.ModelAdmin): radio_fields = {"difficulty": admin.VERTICAL} + fieldsets = ( + ( + None, + { + "fields": ( + ("title", "difficulty"), + ("materials", "start_datetime"), + ("categories"), + ), + }, + ), + ) site = admin.AdminSite(name="admin") diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index ad64762a5192..0ff38397451f 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -7065,10 +7065,10 @@ def test_use_fieldset_fields_render(self): title="Django Class", materials="django_documents" ) expected_legend_tags_text = [ - "Materials:", "Difficulty:", - "Categories:", + "Materials:", "Start datetime:", + "Categories:", ] url = reverse("admin:admin_views_course_change", args=(course.pk,)) self.selenium.get(self.live_server_url + url) @@ -7079,6 +7079,29 @@ def test_use_fieldset_fields_render(self): legend = fieldset.find_element(By.TAG_NAME, "legend") self.assertEqual(legend.text, expected_legend_tags_text[index]) + @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark", "high_contrast"]) + def test_use_fieldset_with_grouped_fields(self): + from selenium.webdriver.common.by import By + + self.admin_login( + username="super", password="secret", login_url=reverse("admin:index") + ) + self.selenium.get( + self.live_server_url + reverse("admin:admin_views_course_add") + ) + multiline = self.selenium.find_element( + By.CSS_SELECTOR, "#content-main .field-difficulty, .form-multiline" + ) + # Two field boxes. + field_boxes = multiline.find_elements(By.CSS_SELECTOR, "div > div.fieldBox") + self.assertEqual(len(field_boxes), 2) + # One of them is under a
. + under_fieldset = multiline.find_elements( + By.CSS_SELECTOR, "fieldset > div > div.fieldBox" + ) + self.assertEqual(len(under_fieldset), 1) + self.take_screenshot("horizontal_fieldset") + @screenshot_cases(["desktop_size", "mobile_size", "rtl", "dark", "high_contrast"]) @override_settings(MESSAGE_LEVEL=10) def test_messages(self):