DRF获取Token登录:如何将默认用户名替换为邮箱?
问题分析与解决方案
问题根源
- 错误使用
ModelSerializer:你用ModelSerializer实现登录序列化器时,它会自动应用AuthUser模型的字段约束(比如邮箱唯一性校验),导致传入已注册邮箱时触发“该邮箱已存在用户”的错误——这完全不符合登录场景的需求。 validate方法未传递用户对象:你的校验方法仅返回了邮箱和密码,没有将验证通过的用户对象存入validated_data,后续视图无法正确获取用户实例。- 多余的
create方法:登录逻辑不需要创建新用户,该方法属于冗余代码,还可能引发逻辑混淆。
修改后的代码实现
1. 自定义登录序列化器
from rest_framework import serializers from .models import AuthUser class AuthTokenSerializer(serializers.Serializer): email = serializers.EmailField() password = serializers.CharField(write_only=True) def validate(self, data): email = data.get('email') password = data.get('password') if not email or not password: raise serializers.ValidationError("请提供邮箱和密码") user = AuthUser.objects.filter(email=email).first() if not user: raise serializers.ValidationError("该邮箱未注册") if not user.check_password(password): raise serializers.ValidationError("密码错误") # 将验证通过的用户对象存入validated_data,供视图调用 data['user'] = user return data
2. 自定义登录视图
from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.response import Response from rest_framework.authtoken.models import Token from .serializers import AuthTokenSerializer class AuthLoginUser(ObtainAuthToken): serializer_class = AuthTokenSerializer 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, 'first_name': user.first_name, 'last_name': user.last_name, 'email': user.email, 'role': user.role })
3. URL配置(保持你的修改)
urlpatterns = [ # ... 其他路由 path('login/', views.AuthLoginUser.as_view()), ]
关键修改说明
- 改用
Serializer替代ModelSerializer:仅定义登录所需的字段,避免模型自带的唯一性校验干扰登录流程。 - 在
validate方法中传递用户对象:验证通过后将用户实例存入validated_data,确保视图能正确获取用户信息生成Token。 - 移除冗余的
create方法:登录逻辑不需要创建新用户,删除后避免逻辑混淆。
内容的提问来源于stack exchange,提问作者Suraj Singh
相关产品推荐
相关产品推荐

