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

Django Guardian开发拉黑功能时assign_perm报权限查询不存在错误

问题根因

permission matching query does not exist错误以及后续逻辑不生效,核心是4个写法和设计问题:

  • 权限标识符格式错误:Django(包括Django Guardian)识别自定义权限必须带所属应用前缀,格式为<app_label>.<permission_codename>,直接传cant_view_profile短名会导致ORM查不到auth_permission表中对应记录。Admin后台能正常分配是因为后台自动补全了app前缀,不存在这个问题。
  • 权限体系关联错误:Profile模型中自定义的group多对多字段和Django内置权限体系无关,Django的用户组、权限逻辑是绑定在默认User模型上的,给Profile实例加组完全不会被权限框架识别。
  • assign_perm参数逻辑颠倒:Guardian的assign_perm方法签名为assign_perm(权限名, 授权主体(用户/用户组), 权限绑定的对象),当前代码写反了授权主体和绑定对象,实际是给blockedusers组分配了针对当前登录用户的权限,和“限制被拉黑用户访问主页”的需求完全不符。
  • 权限设计逻辑错误:用全局用户组绑定权限的思路,会导致所有进入blockedusers组的用户无法访问全站所有用户的主页,不符合拉黑功能“仅禁止访问拉黑者本人主页”的对象级限制需求。
代码修复步骤
  1. 先确认自定义权限已经同步到数据库,执行迁移命令:
python manage.py makemigrations
python manage.py migrate
  1. 删掉Profile模型中自定义的group字段,直接使用Django User模型内置的groups关联即可,不需要重复定义。
  2. 修正视图中的权限标识符和参数逻辑,注意把profiles替换成Profile模型所在的实际app名称:
def block_user_view(request, id):
    if request.method == "POST":
        blocked_group = Group.objects.get(name="blockedusers")
        # 拿到被拉黑用户对应的User对象,而非Profile实例
        blocked_user = Profile.objects.get(id=id).user
        current_user_profile = request.user.profile
        # 给blockedusers组分配「不能查看当前用户主页」的对象级权限,绑定当前用户的Profile实例
        assign_perm("profiles.cant_view_profile", blocked_group, current_user_profile)
        # 把被拉黑用户加入blocked组
        blocked_user.groups.add(blocked_group)
        # 权限校验
        print(blocked_user.has_perm("profiles.cant_view_profile", current_user_profile))

    return render(request, "profiles/blockuser.html", {})
  1. 在用户主页访问视图中增加权限校验,被限制的用户直接返回403:
from django.http import HttpResponseForbidden

def profile_detail_view(request, user_id):
    profile = Profile.objects.get(user_id=user_id)
    # 校验当前用户是否有查看该主页的权限
    if request.user.has_perm("profiles.cant_view_profile", profile):
        return HttpResponseForbidden("你已被该用户拉黑,无法访问主页")
    return render(request, "profiles/detail.html", {"profile": profile})
更轻量的替代实现方案

如果拉黑功能不需要复杂的权限组合,完全没必要引入Guardian,直接用多对多字段存黑名单即可,逻辑更简单、性能更好:

  1. 在Profile模型中增加黑名单关联字段:
class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    prof_pics = models.ImageField(null=True, blank=True, upload_to='images/')
    friends = models.ManyToManyField(User, blank=True, related_name="friend")
    bio = models.TextField(blank=True)
    # 存储所有被当前用户拉黑的用户
    blocked_users = models.ManyToManyField(User, blank=True, related_name="blocked_by")

    def __str__(self):
        return str(self.user)
  1. 拉黑视图直接操作关联字段即可,不需要处理权限和用户组:
def block_user_view(request, id):
    if request.method == "POST":
        blocked_user = User.objects.get(profile__id=id)
        request.user.profile.blocked_users.add(blocked_user)
    return render(request, "profiles/blockuser.html", {})
  1. 主页访问时直接判断黑名单:
from django.http import HttpResponseForbidden

def profile_detail_view(request, user_id):
    profile = Profile.objects.get(user_id=user_id)
    # 当前访问用户在黑名单内则直接拦截
    if request.user in profile.blocked_users.all():
        return HttpResponseForbidden("你已被该用户拉黑,无法访问主页")
    return render(request, "profiles/detail.html", {"profile": profile})

该方案没有额外的权限表查询逻辑,不需要维护用户组,后续扩展拉黑后的互动限制(比如禁止评论、禁止发私信)也只需要加一层黑名单判断即可,是中小站点实现拉黑功能的首选方案。

内容的提问来源于stack exchange,提问作者Emmanuel C. O Peters

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 18:51:20