Django的admin是否可以监控django_admin_log?

7

django_admin_log对于监控管理用户的操作非常有用。目前,我可以通过直接查询数据库来实现这一点。是否存在内置功能,使我能够通过Django的管理界面查看所有用户的django_admin_log表?

4个回答

13

你不能只做这个吗:

from django.contrib.admin.models import LogEntry
admin.site.register(LogEntry)
在你的admin.py文件中吗?我刚测试了一下,虽然很简单但它可以工作。
你可能希望更具体地创建一个ModelAdmin类来为LogEntry提供更好的列表视图和一些过滤能力。但那应该可以工作。

嗨,我也遇到了同样的问题,但是我得到了KeyError at /admin/ Log entries错误,我不知道该如何解决它。 - mh-firouzjah

8
这是我的版本。 可用字段的参考。
class LogAdmin(admin.ModelAdmin):
    """Create an admin view of the history/log table"""
    list_display = ('action_time','user','content_type','change_message','is_addition','is_change','is_deletion')
    list_filter = ['action_time','user','content_type']
    ordering = ('-action_time',)
    #We don't want people changing this historical record:
    def has_add_permission(self, request):
        return False
    def has_change_permission(self, request, obj=None):
        #returning false causes table to not show up in admin page :-(
        #I guess we have to allow changing for now
        return True
    def has_delete_permission(self, request, obj=None):
        return False

您可以将字段设置为只读:readonly_fields = ['user', 'content_type', 'object_id', 'object_repr', 'action_flag', 'change_message'] - 您仍然可以单击保存,但无法进行任何更改。 - EvdB

7

以下是一个更详细的管理员配置,用于查看所有日志条目,并依赖于Django 2.1的仅视图权限:

from django.contrib import admin
from django.contrib.admin.models import LogEntry, DELETION
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.urls import reverse

@admin.register(LogEntry)
class LogEntryAdmin(admin.ModelAdmin):
    date_hierarchy = 'action_time'
    readonly_fields = ('action_time',)
    list_filter = ['user', 'content_type']
    search_fields = ['object_repr', 'change_message']
    list_display = ['__str__', 'content_type', 'action_time', 'user', 'object_link']

    # keep only view permission
    def has_add_permission(self, request):
        return False

    def has_change_permission(self, request, obj=None):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

    def object_link(self, obj):
        if obj.action_flag == DELETION:
            link = obj.object_repr
        else:
            ct = obj.content_type
            try:
                link = mark_safe('<a href="%s">%s</a>' % (
                                 reverse('admin:%s_%s_change' % (ct.app_label, ct.model),
                                         args=[obj.object_id]),
                                 escape(obj.object_repr),
                ))
            except NoReverseMatch:
                link = obj.object_repr
        return link
    object_link.admin_order_field = 'object_repr'
    object_link.short_description = 'object'

    def queryset(self, request):
        return super(LogEntryAdmin, self).queryset(request) \
            .prefetch_related('content_type')

它基于这个Django代码片段,结果看起来像这样:

日志条目截图

如果你想在早期的Django版本中使用它,请参阅此答案的早期版本

1
很高兴拥有自定义列表视图 :) - Daniel Rodríguez

1
从我的经验中得出的几点:

  • It's good to make all fields read only. One reason is obviously because those are logs and should not be mutable, but another is performance. If you allow changing users for example, loading of change page on it's own can be issue if you have hundreds of thousands of users as in my case. Otherwise you can use raw_id_fields.
  • Content type filter values are unsorted by model so it's unfriendly, but don't have nice generic solution to share.
  • I also created filter for action as orignal model does not have CHOICES field and using just action_flag as filter will show 1,2,3 as choices, which isn't very user friendly:

    class ActionFlagFilter(admin.SimpleListFilter):
        title = 'Action flag filter'
    
        parameter_name = 'action_flag'
    
        def lookups(self, request, model_admin):
            return (
                (ADDITION, "Add"),
                (CHANGE, "Change"),
                (DELETION, "Delete"),
            )
    
        def queryset(self, request, queryset):
            if self.value():
                return queryset.filter(action_flag=self.value())
            return queryset
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接