From c517b445847667c9b85eafd658a19b8199c3ae4c Mon Sep 17 00:00:00 2001 From: Jason Novinger Date: Thu, 9 Oct 2025 16:08:37 -0500 Subject: [PATCH] Fixes #20542: Add form prefix to `POST` handler in `ObjectEditView` Commit d22246688 added form prefix support to the `GET` handler to fix Markdown preview functionality in quick add modals. The form prefix allows Django to properly namespace field names and IDs when rendering forms within the quick add modal context. However, the corresponding change was not made to the `POST` handler. This created a mismatch where form fields were rendered with the `quickadd-` prefix during `GET` requests, but the `POST` handler instantiated forms without the prefix. When users submitted quick add forms, Django looked for unprefixed field names like `address` and `status` in the `POST` data, but the actual submitted data used prefixed names like `quickadd-address` and `quickadd-status`. This caused validation to fail immediately with "This field is required" errors for all required fields, making every quick add form unusable. The fix adds the same prefix detection logic to the `POST` handler that was added to the `GET` handler, checking for the `_quickadd` parameter in the query string and applying the `quickadd` prefix when present. This ensures consistent form field naming between rendering and validation. A regression test has been added to `MACAddressTestCase` to verify that MAC addresses can be successfully created via the quick add modal, preventing this issue from recurring. This test should be promoted to a template test whenever it becomes possible to determine if a model should support quick-add functionality. --- netbox/dcim/tests/test_views.py | 29 ++++++++++++++++++++- netbox/netbox/views/generic/object_views.py | 3 ++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index 2e6d5ebc58c..91453b44639 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -7,13 +7,14 @@ from django.urls import reverse from netaddr import EUI +from core.models import ObjectType from dcim.choices import * from dcim.constants import * from dcim.models import * from ipam.models import ASN, RIR, VLAN, VRF from netbox.choices import CSVDelimiterChoices, ImportFormatChoices, WeightUnitChoices from tenancy.models import Tenant -from users.models import User +from users.models import ObjectPermission, User from utilities.testing import ViewTestCases, create_tags, create_test_device, post_data from wireless.models import WirelessLAN @@ -3728,3 +3729,29 @@ def setUpTestData(cls): cls.bulk_edit_data = { 'description': 'New description', } + + @tag('regression') # Issue #20542 + @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[]) + def test_create_macaddress_via_quickadd(self): + """ + Test creating a MAC address via quick-add modal (e.g., from Interface form). + Regression test for issue #20542 where form prefix was missing in POST handler. + """ + obj_perm = ObjectPermission(name='Test permission', actions=['add']) + obj_perm.save() + obj_perm.users.add(self.user) + obj_perm.object_types.add(ObjectType.objects.get_for_model(self.model)) + + # Simulate quick-add form submission with 'quickadd-' prefix + formatted_data = post_data(self.form_data) + quickadd_data = {f'quickadd-{k}': v for k, v in formatted_data.items()} + quickadd_data['_quickadd'] = 'True' + + initial_count = self._get_queryset().count() + url = f"{self._get_url('add')}?_quickadd=True&target=id_primary_mac_address" + response = self.client.post(url, data=quickadd_data) + + # Should successfully create the MAC address and return the quick_add_created template + self.assertHttpStatus(response, 200) + self.assertIn(b'quick-add-object', response.content) + self.assertEqual(initial_count + 1, self._get_queryset().count()) diff --git a/netbox/netbox/views/generic/object_views.py b/netbox/netbox/views/generic/object_views.py index 4e8c3ad8653..89719159209 100644 --- a/netbox/netbox/views/generic/object_views.py +++ b/netbox/netbox/views/generic/object_views.py @@ -281,7 +281,8 @@ def post(self, request, *args, **kwargs): obj = self.alter_object(obj, request, args, kwargs) - form = self.form(data=request.POST, files=request.FILES, instance=obj) + form_prefix = 'quickadd' if request.GET.get('_quickadd') else None + form = self.form(data=request.POST, files=request.FILES, instance=obj, prefix=form_prefix) restrict_form_fields(form, request.user) if form.is_valid():