Django自定义用户模型request.user.groups返回auth.Group.None排查
问题原因
数据库层面用户和组的关联已经正常写入,说明关联中间表数据没问题,request.user.groups返回auth.Group.None本质是模型层的多对多关系映射异常,通常是后期追加PermissionsMixin继承时迁移不完整、字段冲突导致的。另外注意:直接打印多对多字段返回的是关系管理器对象,本身就会显示为模型名.None格式,需要调用.all()才能拿到实际关联数据,这是Django ORM的正常表现,不是报错。
排查步骤
- 检查
UserProfile模型代码,确认没有手动定义groups、user_permissions同名的字段或属性,避免覆盖PermissionsMixin自带的关系定义。 - 检查追加
PermissionsMixin时生成的迁移文件,确认operations里包含groups、user_permissions两个多对多字段的创建操作,很多时候因为初始模型存在残留结构,makemigrations会漏生成这部分操作。 - 进入Django shell执行以下代码,验证模型字段是否正常加载:
from 你的应用名.models import UserProfile # 检查是否存在groups属性 print(hasattr(UserProfile, 'groups')) # 打印字段配置 print(UserProfile._meta.get_field('groups'))
如果返回False或者报字段不存在错误,说明多对多关系没有正确挂载到模型上。
- 检查
settings.py里的AUTH_USER_MODEL配置是否正确指向你的UserProfile模型,配置错误会导致权限关联关系映射到默认的auth.User模型上,和自定义用户模型脱节。
修复方案
- 清理冲突字段:删除
UserProfile里手动定义的groups、user_permissions字段,这两个字段默认由PermissionsMixin提供,不需要手动声明。如果存在反向名冲突(启动服务时报related_name冲突错误),可以手动声明两个字段并指定唯一的related_name:
from django.contrib.auth.models import Group, Permission class UserProfile(AbstractBaseUser, PermissionsMixin): # 原有字段保持不变 email = models.EmailField( verbose_name='email address', max_length=255, unique=True, ) USERNAME_FIELD = 'email' REQUIRED_FIELDS = ['first_name', 'last_name'] first_name = models.CharField(max_length=50, blank=True, null=True) middle_name = models.CharField(max_length=50, blank=True, null=True) last_name = models.CharField(max_length=50, blank=True, null=True) # 仅当出现反向名冲突时追加以下字段声明,无冲突可省略 groups = models.ManyToManyField( Group, verbose_name='用户组', blank=True, related_name="user_profiles", related_query_name="user_profile", ) user_permissions = models.ManyToManyField( Permission, verbose_name='用户权限', blank=True, related_name="user_profiles", related_query_name="user_profile", )
- 补全迁移:如果之前的迁移漏了两个多对多字段的创建,执行命令重新生成迁移:
python manage.py makemigrations 你的应用名
如果makemigrations没有检测到变更,可以手动在最新的迁移文件里追加两个多对多字段的AddField操作,注意保持迁移依赖正确。
3. 执行迁移同步数据库结构:
python manage.py migrate
- 验证:重启服务后修改测试代码,调用
.all()方法获取实际关联数据:
for group in Group.objects.all(): print(group, group.id) request.user.groups.add(Group.objects.get(id=2)) print(Group.objects.get(user=request.user)) print(request.user.groups.all()) # 必须加.all()才能拿到实际查询结果
正常情况下最后一行会输出<QuerySet [<Group: business_customers>]>,问题修复完成。
内容的提问来源于stack exchange,提问作者mrabot
相关产品推荐
相关产品推荐

