mirror of https://github.com/django/django.git
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().
This commit is contained in:
parent
1964e4367f
commit
473283d241
|
@ -336,6 +336,7 @@ class AdminSite:
|
||||||
"available_apps": self.get_app_list(request),
|
"available_apps": self.get_app_list(request),
|
||||||
"is_popup": False,
|
"is_popup": False,
|
||||||
"is_nav_sidebar_enabled": self.enable_nav_sidebar,
|
"is_nav_sidebar_enabled": self.enable_nav_sidebar,
|
||||||
|
"log_entries": self.get_log_entries(request),
|
||||||
}
|
}
|
||||||
|
|
||||||
def password_change(self, request, extra_context=None):
|
def password_change(self, request, extra_context=None):
|
||||||
|
@ -588,6 +589,11 @@ class AdminSite:
|
||||||
context,
|
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):
|
class DefaultAdminSite(LazyObject):
|
||||||
def _setup(self):
|
def _setup(self):
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from django import template
|
from django import template
|
||||||
from django.contrib.admin.models import LogEntry
|
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
@ -12,16 +11,13 @@ class AdminLogNode(template.Node):
|
||||||
return "<GetAdminLog Node>"
|
return "<GetAdminLog Node>"
|
||||||
|
|
||||||
def render(self, context):
|
def render(self, context):
|
||||||
if self.user is None:
|
entries = context["log_entries"]
|
||||||
entries = LogEntry.objects.all()
|
if self.user is not None:
|
||||||
else:
|
|
||||||
user_id = self.user
|
user_id = self.user
|
||||||
if not user_id.isdigit():
|
if not user_id.isdigit():
|
||||||
user_id = context[self.user].pk
|
user_id = context[self.user].pk
|
||||||
entries = LogEntry.objects.filter(user__pk=user_id)
|
entries = entries.filter(user__pk=user_id)
|
||||||
context[self.varname] = entries.select_related("content_type", "user")[
|
context[self.varname] = entries[: int(self.limit)]
|
||||||
: int(self.limit)
|
|
||||||
]
|
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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_popup``: whether the current page is displayed in a popup window
|
||||||
* ``is_nav_sidebar_enabled``: :attr:`AdminSite.enable_nav_sidebar`
|
* ``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)
|
.. 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
|
Raises ``django.contrib.admin.sites.NotRegistered`` if a model isn't
|
||||||
already registered.
|
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-to-urlconf:
|
||||||
|
|
||||||
Hooking ``AdminSite`` instances into your URLconf
|
Hooking ``AdminSite`` instances into your URLconf
|
||||||
|
|
|
@ -43,7 +43,8 @@ Minor features
|
||||||
:mod:`django.contrib.admin`
|
: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`
|
:mod:`django.contrib.admindocs`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -1595,7 +1595,12 @@ class GetAdminLogTests(TestCase):
|
||||||
{% get_admin_log %} works if the user model's primary key isn't named
|
{% get_admin_log %} works if the user model's primary key isn't named
|
||||||
'id'.
|
'id'.
|
||||||
"""
|
"""
|
||||||
context = Context({"user": CustomIdUser()})
|
context = Context(
|
||||||
|
{
|
||||||
|
"user": CustomIdUser(),
|
||||||
|
"log_entries": LogEntry.objects.all(),
|
||||||
|
}
|
||||||
|
)
|
||||||
template = Template(
|
template = Template(
|
||||||
"{% load log %}{% get_admin_log 10 as admin_log for_user user %}"
|
"{% load log %}{% get_admin_log 10 as admin_log for_user user %}"
|
||||||
)
|
)
|
||||||
|
@ -1608,6 +1613,7 @@ class GetAdminLogTests(TestCase):
|
||||||
user.save()
|
user.save()
|
||||||
ct = ContentType.objects.get_for_model(User)
|
ct = ContentType.objects.get_for_model(User)
|
||||||
LogEntry.objects.log_action(user.pk, ct.pk, user.pk, repr(user), 1)
|
LogEntry.objects.log_action(user.pk, ct.pk, user.pk, repr(user), 1)
|
||||||
|
context = Context({"log_entries": LogEntry.objects.all()})
|
||||||
t = Template(
|
t = Template(
|
||||||
"{% load log %}"
|
"{% load log %}"
|
||||||
"{% get_admin_log 100 as admin_log %}"
|
"{% get_admin_log 100 as admin_log %}"
|
||||||
|
@ -1615,7 +1621,7 @@ class GetAdminLogTests(TestCase):
|
||||||
"{{ entry|safe }}"
|
"{{ entry|safe }}"
|
||||||
"{% endfor %}"
|
"{% endfor %}"
|
||||||
)
|
)
|
||||||
self.assertEqual(t.render(Context({})), "Added “<User: jondoe>”.")
|
self.assertEqual(t.render(context), "Added “<User: jondoe>”.")
|
||||||
|
|
||||||
def test_missing_args(self):
|
def test_missing_args(self):
|
||||||
msg = "'get_admin_log' statements require two arguments"
|
msg = "'get_admin_log' statements require two arguments"
|
||||||
|
|
|
@ -35,3 +35,19 @@ site = admin.AdminSite(name="admin")
|
||||||
site.register(Article)
|
site.register(Article)
|
||||||
site.register(ArticleProxy)
|
site.register(ArticleProxy)
|
||||||
site.register(Site, SiteAdmin)
|
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)
|
||||||
|
|
|
@ -10,7 +10,7 @@ from django.urls import reverse
|
||||||
from django.utils import translation
|
from django.utils import translation
|
||||||
from django.utils.html import escape
|
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")
|
@override_settings(ROOT_URLCONF="admin_utils.urls")
|
||||||
|
@ -318,3 +318,30 @@ class LogEntryTests(TestCase):
|
||||||
with self.subTest(action_flag=action_flag):
|
with self.subTest(action_flag=action_flag):
|
||||||
log = LogEntry(action_flag=action_flag)
|
log = LogEntry(action_flag=action_flag)
|
||||||
self.assertEqual(log.get_action_flag_display(), display_name)
|
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")
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from .admin import site
|
from .admin import custom_site, site
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("test_admin/admin/", site.urls),
|
path("test_admin/admin/", site.urls),
|
||||||
|
path("test_admin/custom_admin/", custom_site.urls),
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue