Django REST接入LogEntry记录用户活动及Token认证下查询变更问题
核心问题原因
Django内置的LogEntry默认仅自动记录Admin站点内的操作,你通过SimpleJWT认证访问DRF接口的操作,默认不会触发LogEntry的写入逻辑,因此查询不到对应变更数据。
解决方案
1. 实现接口操作自动写入LogEntry
通过DRF自定义Mixin实现通用日志逻辑,不需要为每个接口的每个方法单独写代码:
首先创建通用日志混入类:
# mixins.py from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION from django.contrib.contenttypes.models import ContentType class AutoLogMixin: def perform_create(self, serializer): instance = serializer.save() content_type = ContentType.objects.get_for_model(instance) LogEntry.objects.log_action( user_id=self.request.user.id, content_type_id=content_type.pk, object_id=instance.pk, object_repr=str(instance), action_flag=ADDITION, change_message="API创建资源" ) return instance def perform_update(self, serializer): instance = serializer.save() content_type = ContentType.objects.get_for_model(instance) LogEntry.objects.log_action( user_id=self.request.user.id, content_type_id=content_type.pk, object_id=instance.pk, object_repr=str(instance), action_flag=CHANGE, change_message="API更新资源" ) return instance def perform_destroy(self, instance): content_type = ContentType.objects.get_for_model(instance) object_repr = str(instance) # 删除前先写入日志,避免实例删除后无法获取属性 LogEntry.objects.log_action( user_id=self.request.user.id, content_type_id=content_type.pk, object_id=instance.pk, object_repr=object_repr, action_flag=DELETION, change_message="API删除资源" ) instance.delete()
之后所有需要记录日志的业务ViewSet,直接继承该Mixin即可自动记录增删改操作:
# 业务ViewSet示例 class YourBusinessViewSet(AutoLogMixin, viewsets.ModelViewSet): queryset = YourModel.objects.all() serializer_class = YourModelSerializer
如果需要全项目所有接口都生效,直接修改你项目的公共BaseViewSet,让所有业务ViewSet继承的基类先继承AutoLogMixin即可,无需逐个修改。
2. 适配SimpleJWT认证的LogEntry查询接口
修改你现有的LogEntryViewSet,启用JWT认证,同时可以按用户权限返回对应日志:
# viewsets.py from rest_framework.permissions import IsAuthenticated from rest_framework_simplejwt.authentication import JWTAuthentication class LogEntryViewSet(viewsets.ModelViewSet): # 启用JWT认证 authentication_classes = [JWTAuthentication] # 要求登录才可访问 permission_classes = [IsAuthenticated] serializer_class = LogEntrySerializer def get_queryset(self): user = self.request.user # 超级管理员可查看所有日志 if user.is_superuser: return LogEntry.objects.all() # 普通用户仅查看自身操作生成的日志 return LogEntry.objects.filter(user=user)
可选优化
如果需要记录具体字段变更内容,可在perform_update方法中加入新旧字段对比逻辑,将差异内容写入change_message字段即可。
内容的提问来源于stack exchange,提问作者elias_oliveira
相关产品推荐
相关产品推荐

