mirror of
https://github.com/jazzband/django-auditlog.git
synced 2026-03-16 22:20:26 +00:00
Introduce admin filter by changed field
This commit is contained in:
parent
5cd55ac38c
commit
f58b3d7685
2 changed files with 40 additions and 3 deletions
|
|
@ -6,7 +6,7 @@ from django.utils.functional import cached_property
|
|||
|
||||
from .models import LogEntry
|
||||
from .mixins import LogEntryAdminMixin
|
||||
from .filters import ResourceTypeFilter
|
||||
from .filters import ResourceTypeFilter, FieldFilter
|
||||
|
||||
|
||||
class TimeLimitedPaginator(Paginator):
|
||||
|
|
@ -30,7 +30,7 @@ class TimeLimitedPaginator(Paginator):
|
|||
class LogEntryAdmin(admin.ModelAdmin, LogEntryAdminMixin):
|
||||
list_display = ['created', 'resource_url', 'action', 'msg_short', 'user_url']
|
||||
search_fields = ['timestamp', 'object_repr', 'changes', 'actor__first_name', 'actor__last_name']
|
||||
list_filter = ['action', ResourceTypeFilter]
|
||||
list_filter = ['action', ResourceTypeFilter, FieldFilter]
|
||||
readonly_fields = ['created', 'resource_url', 'action', 'user_url', 'msg']
|
||||
fieldsets = [
|
||||
(None, {'fields': ['created', 'user_url', 'resource_url']}),
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
from django.contrib.admin import SimpleListFilter
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.postgres.fields import JSONField
|
||||
from django.db import connection
|
||||
from django.db.models import Value
|
||||
from django.db.models.functions import Concat
|
||||
from django.db.models.functions import Concat, Cast
|
||||
|
||||
from auditlog.registry import auditlog
|
||||
|
||||
|
|
@ -27,3 +29,38 @@ class ResourceTypeFilter(SimpleListFilter):
|
|||
if self.value() is None:
|
||||
return queryset
|
||||
return queryset.filter(content_type_id=self.value())
|
||||
|
||||
|
||||
class FieldFilter(SimpleListFilter):
|
||||
title = 'Field'
|
||||
parameter_name = 'field'
|
||||
parent = ResourceTypeFilter
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
self.target_model = self._get_target_model(request)
|
||||
super().__init__(request, *args, **kwargs)
|
||||
|
||||
def _get_target_model(self, request):
|
||||
# the parameters consumed by previous filters aren't passed to subsequent filters,
|
||||
# so we have to look into the request parameters explicitly
|
||||
content_type_id = request.GET.get(self.parent.parameter_name)
|
||||
if not content_type_id:
|
||||
return None
|
||||
|
||||
return ContentType.objects.get(id=content_type_id).model_class()
|
||||
|
||||
def lookups(self, request, model_admin):
|
||||
if connection.vendor != 'postgresql':
|
||||
# filtering inside JSON is PostgreSQL-specific for now
|
||||
return []
|
||||
if not self.target_model:
|
||||
return []
|
||||
return [(field.name, field.name) for field in self.target_model._meta.fields]
|
||||
|
||||
def queryset(self, request, queryset):
|
||||
if self.value() is None:
|
||||
return queryset
|
||||
return (
|
||||
queryset.annotate(changes_json=Cast("changes", JSONField()))
|
||||
.filter(**{'changes_json__{}__isnull'.format(self.value()): False})
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue