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

使用Django REST Framework登录遇KeyError: 'user'及最优实现咨询

嘿,咱们来解决你的问题,顺便聊聊DRF实现登录的最优方案~

先搞定你的KeyError: 'user'问题

你遇到这个错误的核心原因是:当序列化器验证失败(比如邮箱/密码错误)时,没有往data里注入user键,但视图里依然尝试获取它。咱们来修改序列化器,把这个坑填上:

修复后的序列化器代码

from rest_framework import serializers
from django.contrib.auth import authenticate
from django.contrib.auth.models import User

class LoginSerializers(serializers.Serializer):
    email = serializers.CharField(max_length=255)
    password = serializers.CharField(max_length=128, write_only=True)

    def validate(self, data):
        email = data.get('email', None)
        password = data.get('password', None)

        # 先检查邮箱和密码是否为空
        if not email or not password:
            raise serializers.ValidationError("邮箱和密码均不能为空")

        # 调用Django自带的认证方法验证用户
        user = authenticate(username=email, password=password)

        # 认证失败直接抛出错误,避免后续代码走到取user的步骤
        if not user:
            raise serializers.ValidationError("邮箱或密码不正确")

        # 可选:确保用户是活跃状态,防止禁用用户登录
        if not user.is_active:
            raise serializers.ValidationError("该用户已被禁用")

        data['user'] = user
        return data

修复要点:

  • 去掉了多余的Meta类(你用的是Serializer而非ModelSerializer,指定model没有实际作用)
  • 添加空值检查,避免authenticate传入无效参数
  • 认证失败时主动抛出ValidationError,让serializer.is_valid(raise_exception=True)直接返回错误响应
  • 增加用户活跃状态校验(可选但推荐)

修改后你的视图类就能正常获取serializer.validated_data['user'],不会再出现KeyError了。

DRF实现登录的最优方案

其实DRF已经提供了成熟的登录解决方案,不用从零手写APIView。根据项目规模和需求,推荐两种主流方案:

方案1:DRF自带Token认证(适合小型项目)

这是最轻量化的实现,DRF内置了全套工具,几步就能搞定:

步骤1:配置项目

在settings.py中添加:

INSTALLED_APPS = [
    # 其他已安装应用
    'rest_framework.authtoken',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.TokenAuthentication',
    ],
}

步骤2:添加路由

在urls.py中引入内置登录视图:

from rest_framework.authtoken.views import obtain_auth_token

urlpatterns = [
    # 其他路由
    path('api/login/', obtain_auth_token, name='api-login'),
]

这个视图默认接收username和password参数,返回token。如果需要自定义返回内容(比如用户ID、邮箱),可以继承ObtainAuthToken重写:

from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.response import Response
from rest_framework import status

class CustomAuthToken(ObtainAuthToken):
    def post(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data, context={'request': request})
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        token, created = Token.objects.get_or_create(user=user)
        return Response({
            'token': token.key,
            'user_id': user.pk,
            'email': user.email
        }, status=status.HTTP_200_OK)

然后把路由换成这个自定义视图即可。

方案2:JWT认证(适合前后端分离/大型项目)

JWT(JSON Web Token)是更安全灵活的方案,支持token过期和刷新机制,推荐用djangorestframework-simplejwt库实现:

步骤1:安装依赖

pip install djangorestframework-simplejwt

步骤2:配置项目

在settings.py中添加:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
}

# 可选:自定义token有效期
from datetime import timedelta
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),  # 访问令牌有效期30分钟
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),     # 刷新令牌有效期1天
}

步骤3:添加路由

在urls.py中引入JWT相关视图:

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)

urlpatterns = [
    # 其他路由
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),  # 获取token
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),  # 刷新token
]
  • api/token/:接收username和password,返回access(访问令牌)和refresh(刷新令牌)
  • api/token/refresh/:接收refresh令牌,返回新的access令牌

方案对比

  • Token认证:实现简单,适合小型、对安全性要求不高的项目;缺点是token无过期时间,除非手动删除否则一直有效。
  • JWT认证:支持过期、刷新机制,安全性更高,适合前后端分离、大型项目;缺点是配置稍复杂,但功能更全面。

内容的提问来源于stack exchange,提问作者unknown

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:07:10