mirror of
https://github.com/django/django.git
synced 2025-05-21 14:26:29 +00:00
[5.2.x] Fixed #36234 -- Restored single_object argument to LogEntry.objects.log_actions().
Thank you Adam Johnson for the report and fix. Thank you Sarah Boyce for your spot on analysis. Regression in c09bceef68e5abb79accedd12dade16aa6577a09, which is partially reverted in this branch. Co-authored-by: Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> Backport of 27b68bcadf1ab2e9f7fd223aed42db352ccdc62d from main.
This commit is contained in:
parent
5fdc951f43
commit
95031c1ab1
@ -51,7 +51,9 @@ class LogEntryManager(models.Manager):
|
|||||||
change_message=change_message,
|
change_message=change_message,
|
||||||
)
|
)
|
||||||
|
|
||||||
def log_actions(self, user_id, queryset, action_flag, change_message=""):
|
def log_actions(
|
||||||
|
self, user_id, queryset, action_flag, change_message="", *, single_object=False
|
||||||
|
):
|
||||||
# RemovedInDjango60Warning.
|
# RemovedInDjango60Warning.
|
||||||
if type(self).log_action != LogEntryManager.log_action:
|
if type(self).log_action != LogEntryManager.log_action:
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
@ -94,7 +96,9 @@ class LogEntryManager(models.Manager):
|
|||||||
if len(log_entry_list) == 1:
|
if len(log_entry_list) == 1:
|
||||||
instance = log_entry_list[0]
|
instance = log_entry_list[0]
|
||||||
instance.save()
|
instance.save()
|
||||||
return instance
|
if single_object:
|
||||||
|
return instance
|
||||||
|
return [instance]
|
||||||
|
|
||||||
return self.model.objects.bulk_create(log_entry_list)
|
return self.model.objects.bulk_create(log_entry_list)
|
||||||
|
|
||||||
|
@ -955,6 +955,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
queryset=[obj],
|
queryset=[obj],
|
||||||
action_flag=ADDITION,
|
action_flag=ADDITION,
|
||||||
change_message=message,
|
change_message=message,
|
||||||
|
single_object=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def log_change(self, request, obj, message):
|
def log_change(self, request, obj, message):
|
||||||
@ -970,6 +971,7 @@ class ModelAdmin(BaseModelAdmin):
|
|||||||
queryset=[obj],
|
queryset=[obj],
|
||||||
action_flag=CHANGE,
|
action_flag=CHANGE,
|
||||||
change_message=message,
|
change_message=message,
|
||||||
|
single_object=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
def log_deletion(self, request, obj, object_repr):
|
def log_deletion(self, request, obj, object_repr):
|
||||||
|
@ -9,4 +9,6 @@ Django 5.1.8 fixes several bugs in 5.1.7.
|
|||||||
Bugfixes
|
Bugfixes
|
||||||
========
|
========
|
||||||
|
|
||||||
* ...
|
* Fixed a regression in Django 5.1.7 where the removal of the ``single_object``
|
||||||
|
parameter unintentionally altered the signature and return type of
|
||||||
|
``LogEntryManager.log_actions()`` (:ticket:`36234`).
|
||||||
|
@ -271,12 +271,13 @@ class LogEntryTests(TestCase):
|
|||||||
content_type = ContentType.objects.get_for_model(self.a1)
|
content_type = ContentType.objects.get_for_model(self.a1)
|
||||||
self.assertEqual(len(queryset), 3)
|
self.assertEqual(len(queryset), 3)
|
||||||
with self.assertNumQueries(1):
|
with self.assertNumQueries(1):
|
||||||
LogEntry.objects.log_actions(
|
result = LogEntry.objects.log_actions(
|
||||||
self.user.pk,
|
self.user.pk,
|
||||||
queryset,
|
queryset,
|
||||||
DELETION,
|
DELETION,
|
||||||
change_message=msg,
|
change_message=msg,
|
||||||
)
|
)
|
||||||
|
self.assertEqual(len(result), len(queryset))
|
||||||
logs = (
|
logs = (
|
||||||
LogEntry.objects.filter(action_flag=DELETION)
|
LogEntry.objects.filter(action_flag=DELETION)
|
||||||
.order_by("id")
|
.order_by("id")
|
||||||
@ -300,6 +301,18 @@ class LogEntryTests(TestCase):
|
|||||||
)
|
)
|
||||||
for obj in queryset
|
for obj in queryset
|
||||||
]
|
]
|
||||||
|
result_logs = [
|
||||||
|
(
|
||||||
|
entry.user_id,
|
||||||
|
entry.content_type_id,
|
||||||
|
str(entry.object_id),
|
||||||
|
entry.object_repr,
|
||||||
|
entry.action_flag,
|
||||||
|
entry.change_message,
|
||||||
|
)
|
||||||
|
for entry in result
|
||||||
|
]
|
||||||
|
self.assertSequenceEqual(logs, result_logs)
|
||||||
self.assertSequenceEqual(logs, expected_log_values)
|
self.assertSequenceEqual(logs, expected_log_values)
|
||||||
self.assertEqual(self.signals, [])
|
self.assertEqual(self.signals, [])
|
||||||
|
|
||||||
@ -343,6 +356,40 @@ class LogEntryTests(TestCase):
|
|||||||
]
|
]
|
||||||
self.assertSequenceEqual(log_values, expected_log_values)
|
self.assertSequenceEqual(log_values, expected_log_values)
|
||||||
|
|
||||||
|
def test_log_actions_single_object_param(self):
|
||||||
|
queryset = Article.objects.filter(pk=self.a1.pk)
|
||||||
|
msg = "Deleted Something"
|
||||||
|
content_type = ContentType.objects.get_for_model(self.a1)
|
||||||
|
self.assertEqual(len(queryset), 1)
|
||||||
|
for single_object in (True, False):
|
||||||
|
self.signals = []
|
||||||
|
with self.subTest(single_object=single_object), self.assertNumQueries(1):
|
||||||
|
result = LogEntry.objects.log_actions(
|
||||||
|
self.user.pk,
|
||||||
|
queryset,
|
||||||
|
DELETION,
|
||||||
|
change_message=msg,
|
||||||
|
single_object=single_object,
|
||||||
|
)
|
||||||
|
if single_object:
|
||||||
|
self.assertIsInstance(result, LogEntry)
|
||||||
|
entry = result
|
||||||
|
else:
|
||||||
|
self.assertIsInstance(result, list)
|
||||||
|
self.assertEqual(len(result), 1)
|
||||||
|
entry = result[0]
|
||||||
|
self.assertEqual(entry.user_id, self.user.pk)
|
||||||
|
self.assertEqual(entry.content_type_id, content_type.id)
|
||||||
|
self.assertEqual(str(entry.object_id), str(self.a1.pk))
|
||||||
|
self.assertEqual(entry.object_repr, str(self.a1))
|
||||||
|
self.assertEqual(entry.action_flag, DELETION)
|
||||||
|
self.assertEqual(entry.change_message, msg)
|
||||||
|
expected_signals = [
|
||||||
|
("pre_save", entry),
|
||||||
|
("post_save", entry, True),
|
||||||
|
]
|
||||||
|
self.assertEqual(self.signals, expected_signals)
|
||||||
|
|
||||||
def test_recentactions_without_content_type(self):
|
def test_recentactions_without_content_type(self):
|
||||||
"""
|
"""
|
||||||
If a LogEntry is missing content_type it will not display it in span
|
If a LogEntry is missing content_type it will not display it in span
|
||||||
|
Loading…
x
Reference in New Issue
Block a user