You need to enable JavaScript to run this app. Django Admin中如何配置权限实现用户仅编辑自有模型记录
优惠活动
大模型
产品
解决方案
定价
更多

Django Admin中如何配置权限实现用户仅编辑自有模型记录

Django Admin 实现用户内容访问/编辑隔离的原生方案

所有实现全程依赖Django自带Admin的内置钩子,无需开发独立管理面板、无需引入第三方权限包。

第一步:模型层补全内容归属关联

所有需要做隔离的业务模型,必须新增指向内置User模型的外键字段,用来标记内容所有者,字段设置为不可在Admin表单直接编辑,避免用户篡改归属。
示例模型代码:

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

User = get_user_model()

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    # 内容归属字段
    author = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="user_posts",
        editable=False
    )

class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    author = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="user_comments",
        editable=False
    )

第二步:重写ModelAdmin核心钩子完成隔离

针对每个需要隔离的模型,注册Admin配置类,重写以下几个内置方法实现全流程拦截:

  • 重写get_queryset:过滤所有用户可见的记录集,普通用户仅能拿到自己创建的内容,超管默认保留全量查看权限
  • 重写save_model:新建内容时自动绑定当前登录用户为作者,无需手动选择
  • 重写对象级权限校验方法:在编辑、删除操作触发前,校验当前操作人是否为内容所有者,哪怕用户手动构造请求参数越权,也会被拦截

完整的ModelAdmin配置示例:

from django.contrib import admin
from .models import Post, Comment

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
    list_display = ["title", "created_at", "author"]

    def get_queryset(self, request):
        qs = super().get_queryset(request)
        # 超管不做过滤,保留全量操作权限
        if request.user.is_superuser:
            return qs
        # 普通用户仅返回自己创作的内容
        return qs.filter(author=request.user)

    def save_model(self, request, obj, form, change):
        # 新建对象时自动绑定当前用户为作者
        if not change:
            obj.author = request.user
        super().save_model(request, obj, form, change)

    def has_change_permission(self, request, obj=None):
        # 编辑权限兜底校验:操作具体对象时,必须是所有者才放行
        if obj is not None and obj.author != request.user:
            return False
        return super().has_change_permission(request, obj)

    def has_delete_permission(self, request, obj=None):
        # 删除权限兜底校验
        if obj is not None and obj.author != request.user:
            return False
        return super().has_delete_permission(request, obj)

# Comment的Admin配置和Post逻辑完全一致,照搬上述重写方法即可
@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
    list_display = ["post", "created_at", "author"]

    def get_queryset(self, request):
        qs = super().get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(author=request.user)

    def save_model(self, request, obj, form, change):
        if not change:
            obj.author = request.user
        super().save_model(request, obj, form, change)

    def has_change_permission(self, request, obj=None):
        if obj is not None and obj.author != request.user:
            return False
        return super().has_change_permission(request, obj)

    def has_delete_permission(self, request, obj=None):
        if obj is not None and obj.author != request.user:
            return False
        return super().has_delete_permission(request, obj)

如果多个模型都需要实现相同的隔离逻辑,可以把上述重写方法抽成通用Mixin类,注册Admin时直接继承即可,避免重复编写代码。

第三步:分配普通用户的Admin基础权限

不需要给普通用户开超级管理员权限,通过Django内置的权限组机制分配权限即可:

  • 在Admin的「认证和授权」分类下新建权限组,比如命名为「内容创作者」
  • 给该组勾选对应模型的view/add/change基础权限(如果需要允许普通用户删除自己的内容,再加delete权限)
  • 把所有需要登录Admin管理自有内容的普通用户,加入这个权限组即可

落地注意事项

  • 隔离逻辑必须做两层拦截:查询集过滤负责列表/详情页的可见范围,对象级权限校验负责操作环节的兜底,不能只靠前端隐藏按钮实现隔离
  • 代码中的超管分支必须保留,否则超级管理员也会被限制为仅能查看自己的内容,影响日常运维
  • 归属字段必须设置editable=False,避免用户在表单页手动篡改内容归属人
  • 列表页的批量操作功能会自动基于过滤后的查询集生效,普通用户即使手动构造请求传入其他用户的内容ID,也会因为查询集匹配不到记录被拦截

内容的提问来源于stack exchange,提问作者Pöy Shadman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.24 08:36:03