1
0
mirror of https://github.com/django/django.git synced 2025-10-23 21:59:11 +00:00

Fixed #34462 -- Made admin log actions in bulk.

This also deprecates ModelAdmin.log_deletion() and
LogEntryManager.log_action().
This commit is contained in:
Akash Kumar Sen
2023-06-12 08:50:55 +05:30
committed by Mariusz Felisiak
parent 45e0c5892f
commit 40b3975e7d
12 changed files with 374 additions and 70 deletions

View File

@@ -8,9 +8,10 @@ from django.contrib.contenttypes.models import ContentType
from django.test import TestCase, override_settings
from django.urls import reverse
from django.utils import translation
from django.utils.deprecation import RemovedInDjango60Warning
from django.utils.html import escape
from .models import Article, ArticleProxy, Car, Site
from .models import Article, ArticleProxy, Car, InheritedLogEntryManager, Site
@override_settings(ROOT_URLCONF="admin_utils.urls")
@@ -26,14 +27,22 @@ class LogEntryTests(TestCase):
title="Title",
created=datetime(2008, 3, 12, 11, 54),
)
content_type_pk = ContentType.objects.get_for_model(Article).pk
LogEntry.objects.log_action(
cls.a2 = Article.objects.create(
site=cls.site,
title="Title 2",
created=datetime(2009, 3, 12, 11, 54),
)
cls.a3 = Article.objects.create(
site=cls.site,
title="Title 3",
created=datetime(2010, 3, 12, 11, 54),
)
LogEntry.objects.log_actions(
cls.user.pk,
content_type_pk,
cls.a1.pk,
repr(cls.a1),
[cls.a1],
CHANGE,
change_message="Changed something",
single_object=True,
)
def setUp(self):
@@ -227,18 +236,95 @@ class LogEntryTests(TestCase):
logentry = LogEntry.objects.first()
self.assertEqual(repr(logentry), str(logentry.action_time))
# RemovedInDjango60Warning.
def test_log_action(self):
content_type_pk = ContentType.objects.get_for_model(Article).pk
log_entry = LogEntry.objects.log_action(
self.user.pk,
content_type_pk,
self.a1.pk,
repr(self.a1),
CHANGE,
change_message="Changed something else",
)
msg = "LogEntryManager.log_action() is deprecated. Use log_actions() instead."
content_type_val = ContentType.objects.get_for_model(Article).pk
with self.assertWarnsMessage(RemovedInDjango60Warning, msg):
log_entry = LogEntry.objects.log_action(
self.user.pk,
content_type_val,
self.a1.pk,
repr(self.a1),
CHANGE,
change_message="Changed something else",
)
self.assertEqual(log_entry, LogEntry.objects.latest("id"))
def test_log_actions(self):
queryset = Article.objects.all().order_by("-id")
msg = "Deleted Something"
content_type = ContentType.objects.get_for_model(self.a1)
self.assertEqual(len(queryset), 3)
with self.assertNumQueries(1):
LogEntry.objects.log_actions(
self.user.pk,
queryset,
DELETION,
change_message=msg,
)
logs = (
LogEntry.objects.filter(action_flag=DELETION)
.order_by("id")
.values_list(
"user",
"content_type",
"object_id",
"object_repr",
"action_flag",
"change_message",
)
)
expected_log_values = [
(
self.user.pk,
content_type.id,
str(obj.pk),
str(obj),
DELETION,
msg,
)
for obj in queryset
]
self.assertSequenceEqual(logs, expected_log_values)
# RemovedInDjango60Warning.
def test_log_action_fallback(self):
LogEntry.objects2 = InheritedLogEntryManager()
queryset = Article.objects.all().order_by("-id")
content_type = ContentType.objects.get_for_model(self.a1)
self.assertEqual(len(queryset), 3)
msg = (
"The usage of log_action() is deprecated. Implement log_actions() instead."
)
with self.assertNumQueries(3):
with self.assertWarnsMessage(RemovedInDjango60Warning, msg):
LogEntry.objects2.log_actions(self.user.pk, queryset, DELETION)
log_values = (
LogEntry.objects.filter(action_flag=DELETION)
.order_by("id")
.values_list(
"user",
"content_type",
"object_id",
"object_repr",
"action_flag",
"change_message",
)
)
expected_log_values = [
(
self.user.pk,
content_type.id,
str(obj.pk),
"Test Repr",
DELETION,
"",
)
for obj in queryset
]
self.assertSequenceEqual(log_values, expected_log_values)
def test_recentactions_without_content_type(self):
"""
If a LogEntry is missing content_type it will not display it in span
@@ -248,7 +334,7 @@ class LogEntryTests(TestCase):
link = reverse("admin:admin_utils_article_change", args=(quote(self.a1.pk),))
should_contain = """<a href="%s">%s</a>""" % (
escape(link),
escape(repr(self.a1)),
escape(str(self.a1)),
)
self.assertContains(response, should_contain)
should_contain = "Article"
@@ -320,28 +406,29 @@ class LogEntryTests(TestCase):
self.assertEqual(log.get_action_flag_display(), display_name)
def test_hook_get_log_entries(self):
LogEntry.objects.log_action(
LogEntry.objects.log_actions(
self.user.pk,
ContentType.objects.get_for_model(Article).pk,
self.a1.pk,
"Article changed",
[self.a1],
CHANGE,
change_message="Article changed message",
single_object=True,
)
c1 = Car.objects.create()
LogEntry.objects.log_action(
LogEntry.objects.log_actions(
self.user.pk,
ContentType.objects.get_for_model(Car).pk,
c1.pk,
"Car created",
[c1],
ADDITION,
change_message="Car created message",
single_object=True,
)
exp_str_article = escape(str(self.a1))
exp_str_car = escape(str(c1))
response = self.client.get(reverse("admin:index"))
self.assertContains(response, "Article changed")
self.assertContains(response, "Car created")
self.assertContains(response, exp_str_article)
self.assertContains(response, exp_str_car)
# site "custom_admin" only renders log entries of registered models
response = self.client.get(reverse("custom_admin:index"))
self.assertContains(response, "Article changed")
self.assertNotContains(response, "Car created")
self.assertContains(response, exp_str_article)
self.assertNotContains(response, exp_str_car)