summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Rief <jacob.rief@gmail.com>2023-02-08 18:37:32 +0100
committerGitHub <noreply@github.com>2023-02-08 18:37:32 +0100
commit473283d2414fa4bbf1e38d663fe4a58f49bf72b9 (patch)
tree63e9f30aff3a6b95e47d3e737750e863644945e0
parent1964e4367f293336b47e30af6e10a5eca5fdfb35 (diff)
Fixed #34303 –- Allowed customizing admin site log entry list.
Added AdminSite.get_log_entries() as an override point and made this available to the template via each_context().
-rw-r--r--django/contrib/admin/sites.py6
-rw-r--r--django/contrib/admin/templatetags/log.py12
-rw-r--r--docs/ref/contrib/admin/index.txt10
-rw-r--r--docs/releases/5.0.txt3
-rw-r--r--tests/admin_changelist/tests.py10
-rw-r--r--tests/admin_utils/admin.py16
-rw-r--r--tests/admin_utils/test_logentry.py29
-rw-r--r--tests/admin_utils/urls.py3
8 files changed, 76 insertions, 13 deletions
diff --git a/django/contrib/admin/sites.py b/django/contrib/admin/sites.py
index 34477900f1..61be31d890 100644
--- a/django/contrib/admin/sites.py
+++ b/django/contrib/admin/sites.py
@@ -336,6 +336,7 @@ class AdminSite:
"available_apps": self.get_app_list(request),
"is_popup": False,
"is_nav_sidebar_enabled": self.enable_nav_sidebar,
+ "log_entries": self.get_log_entries(request),
}
def password_change(self, request, extra_context=None):
@@ -588,6 +589,11 @@ class AdminSite:
context,
)
+ def get_log_entries(self, request):
+ from django.contrib.admin.models import LogEntry
+
+ return LogEntry.objects.select_related("content_type", "user")
+
class DefaultAdminSite(LazyObject):
def _setup(self):
diff --git a/django/contrib/admin/templatetags/log.py b/django/contrib/admin/templatetags/log.py
index 098aa640d5..00cd40ff8a 100644
--- a/django/contrib/admin/templatetags/log.py
+++ b/django/contrib/admin/templatetags/log.py
@@ -1,5 +1,4 @@
from django import template
-from django.contrib.admin.models import LogEntry
register = template.Library()
@@ -12,16 +11,13 @@ class AdminLogNode(template.Node):
return "<GetAdminLog Node>"
def render(self, context):
- if self.user is None:
- entries = LogEntry.objects.all()
- else:
+ entries = context["log_entries"]
+ if self.user is not None:
user_id = self.user
if not user_id.isdigit():
user_id = context[self.user].pk
- entries = LogEntry.objects.filter(user__pk=user_id)
- context[self.varname] = entries.select_related("content_type", "user")[
- : int(self.limit)
- ]
+ entries = entries.filter(user__pk=user_id)
+ context[self.varname] = entries[: int(self.limit)]
return ""
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index f6db3dca4f..eb6ae1ecc2 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -2832,6 +2832,7 @@ Templates can override or extend base admin templates as described in
* ``is_popup``: whether the current page is displayed in a popup window
* ``is_nav_sidebar_enabled``: :attr:`AdminSite.enable_nav_sidebar`
+ * ``log_entries``: :meth:`.AdminSite.get_log_entries`
.. method:: AdminSite.get_app_list(request, app_label=None)
@@ -2889,6 +2890,15 @@ Templates can override or extend base admin templates as described in
Raises ``django.contrib.admin.sites.NotRegistered`` if a model isn't
already registered.
+.. method:: AdminSite.get_log_entries(request)
+
+ .. versionadded:: 5.0
+
+ Returns a queryset for the related
+ :class:`~django.contrib.admin.models.LogEntry` instances, shown on the site
+ index page. This method can be overridden to filter the log entries by
+ other criteria.
+
.. _hooking-adminsite-to-urlconf:
Hooking ``AdminSite`` instances into your URLconf
diff --git a/docs/releases/5.0.txt b/docs/releases/5.0.txt
index a6f827e472..8a2499e7d4 100644
--- a/docs/releases/5.0.txt
+++ b/docs/releases/5.0.txt
@@ -43,7 +43,8 @@ Minor features
:mod:`django.contrib.admin`
~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* ...
+* The new :meth:`.AdminSite.get_log_entries` method allows customizing the
+ queryset for the site's listed log entries.
:mod:`django.contrib.admindocs`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/admin_changelist/tests.py b/tests/admin_changelist/tests.py
index a2db24fea1..413d6d4d7f 100644
--- a/tests/admin_changelist/tests.py
+++ b/tests/admin_changelist/tests.py
@@ -1595,7 +1595,12 @@ class GetAdminLogTests(TestCase):
{% get_admin_log %} works if the user model's primary key isn't named
'id'.
"""
- context = Context({"user": CustomIdUser()})
+ context = Context(
+ {
+ "user": CustomIdUser(),
+ "log_entries": LogEntry.objects.all(),
+ }
+ )
template = Template(
"{% load log %}{% get_admin_log 10 as admin_log for_user user %}"
)
@@ -1608,6 +1613,7 @@ class GetAdminLogTests(TestCase):
user.save()
ct = ContentType.objects.get_for_model(User)
LogEntry.objects.log_action(user.pk, ct.pk, user.pk, repr(user), 1)
+ context = Context({"log_entries": LogEntry.objects.all()})
t = Template(
"{% load log %}"
"{% get_admin_log 100 as admin_log %}"
@@ -1615,7 +1621,7 @@ class GetAdminLogTests(TestCase):
"{{ entry|safe }}"
"{% endfor %}"
)
- self.assertEqual(t.render(Context({})), "Added “<User: jondoe>”.")
+ self.assertEqual(t.render(context), "Added “<User: jondoe>”.")
def test_missing_args(self):
msg = "'get_admin_log' statements require two arguments"
diff --git a/tests/admin_utils/admin.py b/tests/admin_utils/admin.py
index 967f37faf3..a7cfcfa6b9 100644
--- a/tests/admin_utils/admin.py
+++ b/tests/admin_utils/admin.py
@@ -35,3 +35,19 @@ site = admin.AdminSite(name="admin")
site.register(Article)
site.register(ArticleProxy)
site.register(Site, SiteAdmin)
+
+
+class CustomAdminSite(admin.AdminSite):
+ def get_log_entries(self, request):
+ from django.contrib.contenttypes.models import ContentType
+
+ log_entries = super().get_log_entries(request)
+ return log_entries.filter(
+ content_type__in=ContentType.objects.get_for_models(
+ *self._registry.keys()
+ ).values()
+ )
+
+
+custom_site = CustomAdminSite(name="custom_admin")
+custom_site.register(Article)
diff --git a/tests/admin_utils/test_logentry.py b/tests/admin_utils/test_logentry.py
index dfa7962b1e..b700fe54b9 100644
--- a/tests/admin_utils/test_logentry.py
+++ b/tests/admin_utils/test_logentry.py
@@ -10,7 +10,7 @@ from django.urls import reverse
from django.utils import translation
from django.utils.html import escape
-from .models import Article, ArticleProxy, Site
+from .models import Article, ArticleProxy, Car, Site
@override_settings(ROOT_URLCONF="admin_utils.urls")
@@ -318,3 +318,30 @@ class LogEntryTests(TestCase):
with self.subTest(action_flag=action_flag):
log = LogEntry(action_flag=action_flag)
self.assertEqual(log.get_action_flag_display(), display_name)
+
+ def test_hook_get_log_entries(self):
+ LogEntry.objects.log_action(
+ self.user.pk,
+ ContentType.objects.get_for_model(Article).pk,
+ self.a1.pk,
+ "Article changed",
+ CHANGE,
+ change_message="Article changed message",
+ )
+ c1 = Car.objects.create()
+ LogEntry.objects.log_action(
+ self.user.pk,
+ ContentType.objects.get_for_model(Car).pk,
+ c1.pk,
+ "Car created",
+ ADDITION,
+ change_message="Car created message",
+ )
+ response = self.client.get(reverse("admin:index"))
+ self.assertContains(response, "Article changed")
+ self.assertContains(response, "Car created")
+
+ # 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")
diff --git a/tests/admin_utils/urls.py b/tests/admin_utils/urls.py
index 1b6a97e4bd..69db6afc46 100644
--- a/tests/admin_utils/urls.py
+++ b/tests/admin_utils/urls.py
@@ -1,7 +1,8 @@
from django.urls import path
-from .admin import site
+from .admin import custom_site, site
urlpatterns = [
path("test_admin/admin/", site.urls),
+ path("test_admin/custom_admin/", custom_site.urls),
]