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

Django5+DRF登录接口问题:如何返回关联角色信息而非ID

解决Django登录返回关联角色信息的问题

问题背景

使用Vue3 + Django5开发应用,登录功能已完成,但返回的用户数据仅包含role_id,需要返回关联的角色名称等信息。现有模型、序列化器及视图代码如下,尝试select_related时出现字段错误,且无法获取角色信息。

现有模型代码

class Role(models.Model):
    id_role = models.AutoField(primary_key=True)
    name = models.TextField(max_length=100)
    permissions = models.ManyToManyField(Permission)

    def __str__(self):
        return self.name

class User(models.Model):
    id_user = models.AutoField(primary_key=True)
    email = models.TextField(max_length=100)
    password = models.CharField(max_length=255)
    role_id = models.ForeignKey(Role, on_delete=models.PROTECT)
    locale = models.TextField(max_length=5)

    def __str__(self):
        return self.email

现有序列化器代码

class RoleSerializer(ModelSerializer):
    class Meta:
        model = Role
        fields = ('id_role', 'name', 'permissions')

class UserSerializer(ModelSerializer):
    class Meta:
        model = User
        fields = ('id_user', 'email', 'password', 'role_id', 'locale')

现有视图登录方法及错误

原登录方法使用Django自带的serializers.serialize,尝试select_related('roles')时触发字段错误(提示有效字段为role_id),改用role_id后仍无法返回角色信息。


解决方案

1. 修正UserSerializer,嵌套RoleSerializer

在UserSerializer中,将role_id字段替换为RoleSerializer实例,序列化时会自动带出关联的角色信息:

class UserSerializer(ModelSerializer):
    # 嵌套RoleSerializer,关联role_id外键字段
    role_id = RoleSerializer()

    class Meta:
        model = User
        fields = ('id_user', 'email', 'password', 'role_id', 'locale')
        # 可选:设置密码仅写入不返回,避免泄露
        extra_kwargs = {
            'password': {'write_only': True}
        }

2. 重构登录视图方法,使用自定义序列化器

原代码用的Django自带serializers.serialize无法识别自定义嵌套序列化器,需改用UserSerializer处理,同时用select_related预加载关联数据优化查询:

from django.contrib.auth.hashers import check_password

class UserViewSet(viewsets.ModelViewSet):
    serializer_class = UserSerializer
    queryset = User.objects.all()

    @action(detail=False, methods=['post'])
    def login(self, request, pk=None):
        email = request.data.get("email")
        password = request.data.get("password")
        
        # 预加载role_id关联的Role数据,避免N+1查询
        user = User.objects.select_related('role_id').filter(email=email).first()
        
        # 必须用check_password验证,不要直接对比明文(前提是创建用户时用make_password加密)
        if user and check_password(password, user.password):
            serializer = self.get_serializer(user)
            return Response(serializer.data)
        else:
            return Response({"error": "用户不存在或密码错误"}, status=status.HTTP_400_BAD_REQUEST)

3. 密码加密补充(重要)

如果当前用户密码是明文存储,需修改用户创建逻辑,使用Django密码加密工具:

from django.contrib.auth.hashers import make_password

# 创建用户时加密密码
user = User(
    email=request.data["email"],
    password=make_password(request.data["password"]),
    role_id=role_instance,
    locale=request.data["locale"]
)
user.save()

错误原因说明

  1. select_related('roles')报错:模型中User的外键字段名是role_id,不是roles,必须传入正确的字段名role_id。
  2. 无法返回角色信息:原代码用的serializers.serialize是Django底层序列化工具,不会应用自定义ModelSerializer的嵌套配置,因此无法处理关联数据序列化。

内容的提问来源于stack exchange,提问作者Dairelys García Rivas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 21:09:57