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

自定义User类下迁移至django-guardian权限的问题

迁移至Guardian权限系统的规范方案及自定义User类适配方法

看起来你在把项目迁移到Guardian权限系统时遇到了自定义User类的识别问题,我来帮你梳理下规范的迁移步骤,以及解决guardian.exceptions.NotUserNorGroup错误的具体方法。

一、先确保Guardian能识别你的自定义User类

Guardian默认依赖Django的AUTH_USER_MODEL设置,所以第一步要确认你的项目已经正确配置了自定义User类:

  1. 在settings.py中指定AUTH_USER_MODEL
    确保你的EmailUser已经被设置为项目的默认用户模型:

    AUTH_USER_MODEL = "your_app.EmailUser"  # 替换成你的app名和模型名
    

    注意:这个设置最好在项目初始迁移前就配置好,如果是中途修改,可能需要重新初始化数据库(或者做复杂的迁移调整,所以尽量一开始就设置)。

  2. 确认EmailUser的继承结构
    你的EmailUser需要继承自AbstractUser或者AbstractBaseUser,并且配置了必要的管理器(比如UserManager),确保它是Django认可的用户模型。

  3. Guardian的自动适配
    只要AUTH_USER_MODEL配置正确,Guardian会自动识别你的自定义User类,不需要额外配置(除非你有特殊的自定义权限后端需求)。

二、规范的Guardian迁移流程

接下来是从无到有迁移到Guardian的标准步骤,避免踩坑:

1. 安装并配置Guardian

  • 先安装Guardian:pip install django-guardian
  • 在INSTALLED_APPS中添加:
    INSTALLED_APPS = [
        # ... 其他应用
        "guardian",
    ]
    
  • 在AUTHENTICATION_BACKENDS中添加Guardian的权限后端:
    AUTHENTICATION_BACKENDS = [
        "django.contrib.auth.backends.ModelBackend",  # 保留Django默认的后端
        "guardian.backends.ObjectPermissionBackend",  # 添加Guardian的对象权限后端
    ]
    

2. 创建自定义权限(如果需要)

你已经完成了这一步,不过要注意:自定义权限的迁移文件应该基于你的业务模型来创建,比如给Post模型添加can_edit_private_posts权限,迁移文件示例:

from django.db import migrations

def add_custom_permissions(apps, schema_editor):
    Permission = apps.get_model("auth", "Permission")
    ContentType = apps.get_model("contenttypes", "ContentType")
    post_content_type = ContentType.objects.get(app_label="your_app", model="post")
    
    Permission.objects.create(
        codename="can_edit_private_posts",
        name="Can edit private posts",
        content_type=post_content_type,
    )

class Migration(migrations.Migration):
    dependencies = [
        ("your_app", "0001_initial"),  # 依赖你的模型初始迁移
    ]

    operations = [
        migrations.RunPython(add_custom_permissions),
    ]

3. 在迁移中分配权限(解决你的错误)

你遇到的NotUserNorGroup错误,大概率是因为在迁移中直接导入了EmailUser类,而不是使用Django迁移API的apps.get_model来获取模型实例。迁移中应该用这种方式来避免模型引用问题:

from django.db import migrations

def assign_permissions(apps, schema_editor):
    # 通过apps.get_model获取模型,避免直接导入
    User = apps.get_model("your_app", "EmailUser")
    Permission = apps.get_model("auth", "Permission")
    # 如果是对象级权限,还要获取目标对象模型
    Post = apps.get_model("your_app", "Post")

    # 获取要分配权限的用户
    target_user = User.objects.get(email="user@example.com")
    # 获取要分配的权限
    edit_perm = Permission.objects.get(codename="can_edit_private_posts")
    # 如果是对象级权限,获取目标对象
    target_post = Post.objects.get(id=1)

    # 方式1:使用Guardian的shortcut函数
    from guardian.shortcuts import assign_permission
    # 全局权限(不需要对象):assign_permission(edit_perm, target_user)
    # 对象级权限:
    assign_permission(edit_perm, target_user, target_post)

    # 方式2:直接操作Guardian的底层模型(如果方式1还是报错)
    # UserObjectPermission = apps.get_model("guardian", "UserObjectPermission")
    # UserObjectPermission.objects.create(
    #     user=target_user,
    #     permission=edit_perm,
    #     content_object=target_post,
    # )

class Migration(migrations.Migration):
    dependencies = [
        ("your_app", "0002_add_custom_permissions"),  # 依赖创建权限的迁移
        ("guardian", "0001_initial"),  # 依赖Guardian的初始迁移
    ]

    operations = [
        migrations.RunPython(assign_permissions),
    ]

关键注意点:

  • 绝对不要在迁移中直接from your_app.models import EmailUser,必须用apps.get_model,因为迁移运行时模型的状态可能和当前代码不一致。
  • 如果使用assign_permission还是报错,可以尝试直接创建UserObjectPermission实例,绕开Guardian的类型检查(不过只要AUTH_USER_MODEL配置正确,方式1应该就能正常工作)。

三、额外的注意事项

  • 如果是中途迁移到Guardian,要确保现有用户的权限已经被正确迁移(比如把Django的组权限映射到Guardian的权限)。
  • 测试权限分配是否生效:可以在视图或shell中用guardian.shortcuts.get_perms来验证用户是否拥有指定权限。
  • 如果你需要给匿名用户分配权限,Guardian支持AnonymousUser,直接传入即可。

内容的提问来源于stack exchange,提问作者David R.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:12:36