You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django后台利用LogEntry按添加用户过滤模型,并实现仅作者可修改文章?

解决Django后台按创建用户过滤文章并限制修改权限的问题

嘿,你的需求完全可以实现!而且有两种可行的思路,我帮你拆解清楚,你可以根据自己的情况选择:


👉 推荐方案:给文章模型添加「创建者」字段(更高效可靠)

虽然你提到想用LogEntry,但其实LogEntry是Django内置的操作日志模型,主要用来记录后台的增删改操作,并不是专门用来存储文章创建者的。如果直接在文章模型里加一个关联用户的字段,会更高效、更可靠——毕竟如果文章是通过API、脚本等非后台方式创建的,LogEntry里不会有记录,这时候就没法过滤了。

步骤1:修改文章模型

先给Article模型添加created_by外键,关联到Django的User模型:

from django.db import models
from django.contrib.auth.models import User

class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    # 记录创建该文章的用户
    created_by = models.ForeignKey(
        User, 
        on_delete=models.CASCADE, 
        related_name="authored_articles",
        verbose_name="创建者"
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    # 其他字段...

步骤2:配置ModelAdmin实现过滤和权限控制

在admin.py里自定义ArticleAdmin,实现以下功能:

  • 列表页显示创建者
  • 按创建者过滤文章
  • 普通用户只能看到自己创建的文章
  • 只有超级管理员或文章创建者能修改/删除文章
  • 新增文章时自动把当前登录用户设为创建者
from django.contrib import admin
from .models import Article

class ArticleAdmin(admin.ModelAdmin):
    # 列表页展示的字段
    list_display = ("title", "created_by", "created_at", "updated_at")
    # 右侧过滤栏添加「创建者」选项
    list_filter = ("created_by",)
    # 禁止普通用户修改「创建者」字段
    def get_exclude(self, request, obj=None):
        return ("created_by",) if not request.user.is_superuser else ()

    def get_queryset(self, request):
        """只返回当前用户创建的文章(超级管理员除外)"""
        queryset = super().get_queryset(request)
        if request.user.is_superuser:
            return queryset
        return queryset.filter(created_by=request.user)

    def has_change_permission(self, request, obj=None):
        """只有超级管理员或文章创建者能修改"""
        if request.user.is_superuser:
            return True
        # 如果是列表页(obj为None),允许进入(但get_queryset已经过滤了)
        if obj is None:
            return True
        return obj.created_by == request.user

    def has_delete_permission(self, request, obj=None):
        """删除权限和修改权限逻辑一致"""
        if request.user.is_superuser:
            return True
        if obj is None:
            return True
        return obj.created_by == request.user

    def save_model(self, request, obj, form, change):
        """新增文章时自动设置创建者"""
        if not change:  # 只有新增操作时才设置
            obj.created_by = request.user
        super().save_model(request, obj, form, change)

admin.site.register(Article, ArticleAdmin)

👉 可选方案:用LogEntry实现(无需修改现有模型)

如果你的文章模型已经上线,不想修改结构,确实可以通过LogEntry来关联创建文章的用户——因为用户在后台创建文章时,Django会自动生成一条LogEntry记录,其中action_flag=1代表「添加」操作,user就是创建者,content_type对应Article模型,object_id是文章ID。

步骤1:在ModelAdmin中通过LogEntry过滤文章

from django.contrib import admin
from django.contrib.admin.models import LogEntry, ADDITION
from django.contrib.contenttypes.models import ContentType
from .models import Article
from django.contrib.auth.models import User

class ArticleAdmin(admin.ModelAdmin):
    list_display = ("title", "get_created_by", "created_at")

    def get_queryset(self, request):
        """过滤出当前用户创建的文章"""
        queryset = super().get_queryset(request)
        if request.user.is_superuser:
            return queryset
        
        # 获取当前用户创建的所有文章ID
        article_content_type = ContentType.objects.get_for_model(Article)
        created_article_ids = LogEntry.objects.filter(
            user=request.user,
            content_type=article_content_type,
            action_flag=ADDITION
        ).values_list("object_id", flat=True)
        # 把字符串ID转成整数
        created_article_ids = [int(id_str) for id_str in created_article_ids]
        return queryset.filter(id__in=created_article_ids)

    def has_change_permission(self, request, obj=None):
        """验证用户是否有权修改该文章"""
        if request.user.is_superuser:
            return True
        if obj is None:
            return True
        
        article_content_type = ContentType.objects.get_for_model(Article)
        # 检查是否存在当前用户创建该文章的LogEntry记录
        return LogEntry.objects.filter(
            user=request.user,
            content_type=article_content_type,
            object_id=str(obj.id),
            action_flag=ADDITION
        ).exists()

    def get_created_by(self, obj):
        """从LogEntry中获取文章创建者"""
        article_content_type = ContentType.objects.get_for_model(Article)
        create_log = LogEntry.objects.filter(
            content_type=article_content_type,
            object_id=str(obj.id),
            action_flag=ADDITION
        ).first()
        return create_log.user.username if create_log else "未知"
    get_created_by.short_description = "创建者"

# 自定义过滤组件,实现按创建者过滤
class CreatedByLogFilter(admin.SimpleListFilter):
    title = "创建者"
    parameter_name = "created_by"

    def lookups(self, request, model_admin):
        """获取所有创建过文章的用户选项"""
        article_content_type = ContentType.objects.get_for_model(Article)
        users = User.objects.filter(
            logentry__content_type=article_content_type,
            logentry__action_flag=ADDITION
        ).distinct()
        return [(user.id, user.username) for user in users]

    def queryset(self, request, queryset):
        """根据选中的用户过滤文章"""
        if self.value():
            article_content_type = ContentType.objects.get_for_model(Article)
            article_ids = LogEntry.objects.filter(
                user_id=self.value(),
                content_type=article_content_type,
                action_flag=ADDITION
            ).values_list("object_id", flat=True)
            article_ids = [int(id_str) for id_str in article_ids]
            return queryset.filter(id__in=article_ids)
        return queryset

# 把自定义过滤组件添加到列表过滤栏
ArticleAdmin.list_filter = (CreatedByLogFilter,)

admin.site.register(Article, ArticleAdmin)

📌 两种方案对比

维度方案1(添加创建者字段)方案2(用LogEntry)
查询效率高(直接字段过滤)稍低(关联LogEntry)
兼容性支持所有创建方式(后台/API/脚本)仅支持后台创建的文章
代码复杂度简单直观稍复杂(需要处理LogEntry的关联)
数据可靠性高(直接存储创建者)依赖LogEntry记录,若日志丢失则无法过滤

所以如果你的项目还处于初期,强烈推荐方案1;如果模型已经定型无法修改,再考虑方案2。

内容的提问来源于stack exchange,提问作者Mushtaq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:10:18