Django REST Framework登录API Post方法IF语句无法执行问题
问题描述
使用Django REST Framework开发登录API,用于验证数据库中是否存在指定用户数据:
- 数据库存在正确数据:
pengerja_id=123、password=123 - 测试错误数据:
pengerja_id=555、password=555
测试时发现:
- 输入错误
pengerja_id(如555)时,queryset.exists()返回false,正常执行else逻辑返回404 - 输入正确
pengerja_id(123)时,serializer.is_valid()验证不通过,直接返回400错误,后续代码完全不执行 - 同项目中的
InsertNewMemberView功能正常,代码逻辑与当前登录视图类似
问题分析
核心问题出在AuthorizeMemberSerializer的选型上:
当前使用ModelSerializer作为登录验证的序列化器,而ModelSerializer会自动继承模型字段的验证规则。由于模型中pengerja_id是主键且设置了unique=True,ModelSerializer会默认将其视为“创建新数据”的场景,自动验证该pengerja_id是否已存在——当输入已存在的123时,唯一性验证失败,直接导致serializer.is_valid()返回False,触发400错误。
而InsertNewMemberView功能正常,是因为该视图的业务是创建新用户,测试时输入的都是未存在的pengerja_id,不会触发唯一性验证失败的情况。
另外,当前登录逻辑仅验证pengerja_id是否存在,未验证输入的password是否与数据库匹配,存在功能漏洞。
解决方案
针对登录场景的特殊性,需要:
- 改用普通
Serializer替代ModelSerializer,避免继承模型的唯一性验证规则,仅做输入格式校验 - 完善登录逻辑,同时验证
pengerja_id存在性和密码正确性
修改后的代码
serializers.py
调整AuthorizeMemberSerializer为普通序列化器:
from rest_framework import serializers from .models import COOL_YOUTH_MEMBER # 保留其他序列化器不变... class AuthorizeMemberSerializer(serializers.Serializer): pengerja_id = serializers.CharField(max_length=255) password = serializers.CharField(max_length=255)
views.py
完善AuthorizeMemberView的登录验证逻辑:
# 保留其他视图不变... class AuthorizeMemberView(APIView): serializer_class = AuthorizeMemberSerializer def post(self, request, format=None): serializer = self.serializer_class(data=request.data) if serializer.is_valid(): pengerja_id = serializer.data.get('pengerja_id') password = serializer.data.get('password') # 通过get方法直接获取用户,不存在则抛出异常 try: member = COOL_YOUTH_MEMBER.objects.get(pengerja_id=pengerja_id) # 验证密码是否匹配 if member.password == password: return Response({'Success':'User Verified'}, status=status.HTTP_202_ACCEPTED) else: return Response({'Login Failed':'Incorrect password'}, status=status.HTTP_401_UNAUTHORIZED) except COOL_YOUTH_MEMBER.DoesNotExist: return Response({'Login Failed':'User not registered'}, status=status.HTTP_404_NOT_FOUND) # 返回具体的验证错误信息,便于调试 return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
额外提示
- 生产环境中禁止明文存储密码,建议使用Django自带的
make_password和check_password方法加密验证密码 - 可以考虑使用DRF自带的
Authentication类或第三方库实现更规范的登录认证流程
内容的提问来源于stack exchange,提问作者Lukas
相关产品推荐
相关产品推荐

