mirror of
https://github.com/jazzband/django-auditlog.git
synced 2026-03-16 22:20:26 +00:00
104 lines
3.6 KiB
Python
104 lines
3.6 KiB
Python
from functools import cached_property
|
|
|
|
from django.apps import apps
|
|
from django.contrib import admin
|
|
from django.contrib.auth import get_user_model
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
from auditlog.filters import CIDFilter, ResourceTypeFilter
|
|
from auditlog.mixins import LogEntryAdminMixin
|
|
from auditlog.models import LogEntry
|
|
|
|
|
|
@admin.register(LogEntry)
|
|
class LogEntryAdmin(admin.ModelAdmin, LogEntryAdminMixin):
|
|
list_select_related = ["content_type", "actor"]
|
|
list_display = [
|
|
"created",
|
|
"resource_url",
|
|
"action",
|
|
"msg_short",
|
|
"user_url",
|
|
"cid_url",
|
|
]
|
|
search_fields = [
|
|
"timestamp",
|
|
"object_repr",
|
|
"changes",
|
|
"actor__first_name",
|
|
"actor__last_name",
|
|
f"actor__{get_user_model().USERNAME_FIELD}",
|
|
]
|
|
list_filter = ["action", ResourceTypeFilter, CIDFilter]
|
|
readonly_fields = ["created", "resource_url", "action", "user_url", "msg"]
|
|
fieldsets = [
|
|
(None, {"fields": ["created", "user_url", "resource_url", "cid"]}),
|
|
(_("Changes"), {"fields": ["action", "msg"]}),
|
|
]
|
|
|
|
def has_add_permission(self, request):
|
|
return False
|
|
|
|
def has_change_permission(self, request, obj=None):
|
|
return False
|
|
|
|
@cached_property
|
|
def _own_url_names(self):
|
|
return [pattern.name for pattern in self.urls if pattern.name]
|
|
|
|
def has_delete_permission(self, request, obj=None):
|
|
if (
|
|
request.resolver_match
|
|
and request.resolver_match.url_name not in self._own_url_names
|
|
):
|
|
# only allow cascade delete to satisfy delete_related flag
|
|
return super().has_delete_permission(request, obj)
|
|
return False
|
|
|
|
def get_queryset(self, request):
|
|
self.request = request
|
|
queryset = super().get_queryset(request=request)
|
|
|
|
# Check for the `ss` parameter for structured search
|
|
structured_search = request.GET.get("ss")
|
|
if structured_search:
|
|
# Parse structured search term as 'ModelName:id'
|
|
try:
|
|
model_name, object_id = structured_search.split(":")
|
|
object_id = int(object_id)
|
|
except (ValueError, TypeError):
|
|
# If the format is incorrect, return an empty queryset and show a message
|
|
self.message_user(
|
|
request,
|
|
"Structured search format must be 'ModelName:id'.",
|
|
level="warning",
|
|
)
|
|
return queryset.none()
|
|
|
|
# Attempt to retrieve the specified model
|
|
try:
|
|
model = apps.get_model(app_label="api", model_name=model_name)
|
|
if not model:
|
|
raise LookupError
|
|
except LookupError:
|
|
self.message_user(
|
|
request,
|
|
f"Model '{model_name}' does not exist.",
|
|
level="warning",
|
|
)
|
|
return queryset.none()
|
|
|
|
# Attempt to retrieve the object and filter log entries
|
|
try:
|
|
instance = model.objects.get(pk=object_id)
|
|
queryset = LogEntry.objects.get_for_object(instance)
|
|
except ObjectDoesNotExist:
|
|
self.message_user(
|
|
request,
|
|
f"{model_name} instance with ID {object_id} does not exist.",
|
|
level="warning",
|
|
)
|
|
return queryset.none()
|
|
|
|
return queryset # Return filtered or default queryset based on the presence of `ss`
|