【问题标题】:Can django_admin_log be monitored through Django's admin?django_admin_log 可以通过 Django 的 admin 监控吗?
【发布时间】:2010-02-10 21:46:55
【问题描述】:

django_admin_log 表可用于监控管理员中用户的操作。现在,我可以通过直接查询数据库来实现。是否有内置功能可以让我通过 Django 的管理员为所有用户查看表 django_admin_log

【问题讨论】:

    标签: django django-admin


    【解决方案1】:

    你不能:

    from django.contrib.admin.models import LogEntry
    admin.site.register(LogEntry)
    

    在您的某个 admin.py 文件中?我刚刚对其进行了测试,它是准系统,但它可以工作。

    您可能想要更具体一些,并为 LogEntry 创建一个ModelAdmin 类,以提供更好的列表视图和一些过滤功能。但这应该可行。

    【讨论】:

    • 嗨,我也这样做了,但我得到了KeyError at /admin/ Log entries,但我不知道如何解决它
    【解决方案2】:

    这是我的版本。 Reference for fields available.

    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'] - 您仍然可以点击保存,但不能进行任何更改。
    【解决方案3】:

    这是一个更广泛的管理配置,用于查看依赖于 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')
    

    它基于this Django snippet,结果如下所示:

    如果您想将它与早期的 Django 版本一起使用,请参阅此答案的this earlier revision

    【讨论】:

    • 很高兴拥有自定义列表视图:)
    【解决方案4】:

    根据我的经验总结几点:

    • 最好将所有字段设为只读。 一个原因显然是因为这些是日志并且不应该是可变的,但另一个原因是性能。例如,如果您允许更改用户,如果您像我一样拥有数十万用户,则自行加载更改页面可能会成为问题。否则你可以使用raw_id_fields
    • 内容类型过滤器值未按模型排序,因此不友好,但没有很好的通用解决方案可共享。
    • 我还为操作创建了过滤器,因为原始模型没有 CHOICES 字段,并且仅使用 action_flag 作为过滤器将显示 1、2、3 作为选项,这对用户不太友好:

      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
      

    【讨论】:

      猜你喜欢
      • 2016-06-20
      • 2018-08-31
      • 1970-01-01
      • 1970-01-01
      • 2011-06-07
      • 2017-10-14
      • 2011-03-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多