Closes #19713: Enable recording user messages in the change log (#19908)
Some checks are pending
CI / build (20.x, 3.10) (push) Waiting to run
CI / build (20.x, 3.11) (push) Waiting to run
CI / build (20.x, 3.12) (push) Waiting to run

* Add message field to ObjectChange model

* Set max length on changelog message

* Enable changelog messages for single object operations

* Fix tests

* Add changelog message support for bulk edit & bulk delete

* Cosmetic improvements to form fields

* Fix bulk operation templates

* Add message support for bulk import/update

* Add REST API support for changelog messages (WIP)

* Fix changelog_message assignment

* Enable changelog message support for bulk deletions

* Add documentation

* Fix changelog message support for VirtualChassis

* Add ChangeLoggingMixin to necesssary model forms

* Introduce get_random_string() utility function for tests

* Incorporate changelog messages for object view tests

* Incorporate changelog messages for object bulk view tests

* Add missing mixins for changelog message support

* Tweak test to generate expected number of change records

* Finish adding tests for changelog message functionality

* Misc cleanup

* Fixes #19956: Prevent duplicate deletion records from cascading deletions

* Tweak bulk deletion test to work around cascading deletions issue

* Correct API URL
This commit is contained in:
Jeremy Stretch
2025-07-29 10:11:33 -04:00
committed by GitHub
parent 89a94486e1
commit 24a0e1907a
50 changed files with 575 additions and 184 deletions

View File

@@ -346,6 +346,38 @@ class ChangeLogViewTest(ModelViewTestCase):
self.assertEqual(changes[1].changed_object_type, ContentType.objects.get_for_model(Interface))
self.assertEqual(changes[2].changed_object_type, ContentType.objects.get_for_model(Device))
def test_duplicate_deletions(self):
"""
Check that a cascading deletion event does not generate multiple "deleted" ObjectChange records for
the same object.
"""
role1 = DeviceRole(name='Role 1', slug='role-1')
role1.save()
role2 = DeviceRole(name='Role 2', slug='role-2', parent=role1)
role2.save()
pk_list = [role1.pk, role2.pk]
# Delete both objects simultaneously
form_data = {
'pk': pk_list,
'confirm': True,
'_confirm': True,
}
request = {
'path': reverse('dcim:devicerole_bulk_delete'),
'data': post_data(form_data),
}
self.add_permissions('dcim.delete_devicerole')
self.assertHttpStatus(self.client.post(**request), 302)
# This should result in exactly one change record per object
objectchanges = ObjectChange.objects.filter(
changed_object_type=ContentType.objects.get_for_model(DeviceRole),
changed_object_id__in=pk_list,
action=ObjectChangeActionChoices.ACTION_DELETE
)
self.assertEqual(objectchanges.count(), 2)
class ChangeLogAPITest(APITestCase):

View File

@@ -150,7 +150,7 @@ class DataFileTestCase(TestCase, ChangeLoggedFilterSetTests):
class ObjectChangeTestCase(TestCase, BaseFilterSetTests):
queryset = ObjectChange.objects.all()
filterset = ObjectChangeFilterSet
ignore_fields = ('prechange_data', 'postchange_data')
ignore_fields = ('message', 'prechange_data', 'postchange_data')
@classmethod
def setUpTestData(cls):