django-rest-framework - DRF登录api返回E-mail已经存在
问题描述
这是我的模型(自定义用户):
class CustomUser(AbstractUser):
status = models.CharField(_("Record Status"), max_length=1, default='A')
status_dt = models.DateTimeField(_("Status Date"), default=timezone.now)
email = models.CharField(_("E-mail"), max_length=254, unique=True)
record_type = models.CharField(_("Record Type"), max_length=1, default='U')
lang = models.CharField(_("Language"), max_length=2)
name = models.CharField(_("First and Last Name"), max_length=100, blank=True)
photo_main = models.ImageField(_("Profile Picture"), upload_to='photos/%Y/%m/%d/', blank=True)
gender = models.CharField(_("Gender"), max_length=1, default='M')
dtob = models.DateField(_("Birth Date"), blank=True, null=True)
def __str__(self):
return self.email
我有以下序列化程序:
class UserLoginSerializer(serializers.ModelSerializer):
token = serializers.CharField(allow_blank=True, read_only=True)
class Meta:
model = CustomUser
fields = ('email', 'password', 'token',)
extra_kwargs = {
'password': {'write_only': True}
}
def validate(self, data):
print('$$$$$$$$$$$$$$$$$$$$$$$$$ validate $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$')
print('data:')
print(data)
user_obj = None
### E-mail validation
email = data.get("email", None)
if not email:
raise ValidationError(_('email must be filled out.'))
try:
user_obj = get_object_or_404(CustomUser, pk=email)
except CustomUser.DoesNotExist:
raise serializers.ValidationError("E-mail does not exist")
if user_obj and user_obj.status != 'A':
raise serializers.ValidationError("E-mail does not exist")
if not user_obj.exists():
raise ValidationError(_('User does not exist.'))
### Password validation
password = data.get("password", None)
if not password:
raise ValidationError(_('Password must be filled out.'))
if user_obj:
if not user_obj.check_password(password):
raise ValidationError(_('Incorrect credentials. Please try again.'))
elif user_obj.is_active:
data['user'] = user_obj
return data
#################################################################################
这是视图:
class UserLoginAPIView(APIView):
def post(self, request, *args, **kwargs):
data = request.data
serializer = UserLoginSerializer(data=request.data)
if serializer.is_valid():
user = serializer.validated_data['user']
django_login(request, user)
token, created = Token.objects.get_or_create(user=user)
return Response({"token": token.key}, status=status.HTTP_200_OK)
else:
print('%%%%%%%%%%%%%%%%%%%%%%%%%%% serializer errors %%%%%%%%%%%%%%%%%%%%%%%%')
print(serializer.errors)
return Response(data, status=status.HTTP_400_BAD_REQUEST)
当我对我的 api 执行 POST 时,我收到以下错误:
%%%%%%%%%%%%%%%%%%%%%%%%%%序列化错误%%%%%%%%%%%%%%%%%%%% %%% {'email': [ErrorDetail(string='user with this E-mail has already exists.', code='unique')]} 错误请求:/users/api/login/
似乎 Allauth 已拦截该请求并将其验证为注册请求而不是登录。
我试过使用 rest-auth 库,我得到了相同的结果。
关于如何覆盖我猜的 Allauth 的任何建议?
谢谢!
这是我的 users/urls.py 文件:
from django.urls import path, include
from . import views
urlpatterns = [
path("api/register/", registration_view, name="register"),
path("api/login/", views.UserLoginAPIView.as_view(), name="login"),
path("rest-auth/", include('rest_auth.urls')),
]
我正在使用来自 rest_framework authtoken 的令牌:
from django.contrib.auth import get_user_model, login as django_login, logout as django_lougout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse, reverse_lazy
from django.views.generic.edit import CreateView
from django.views.generic import DetailView, RedirectView, UpdateView
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _
from rest_framework.views import APIView
from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.authtoken.models import Token
import allauth
解决方案
哦!我明白了这个问题。您正在使用ModelSerializer根据模型对数据进行序列化。正因为如此,序列化程序正在检查电子邮件是否是唯一的(正如您在模型中定义的那样)。
我们可以对您的代码进行一些改进,但为了使其正常工作并达到validate
功能,您应该更改您的序列化程序。
from rest_framework import serializers
class UserLoginSerializer(serializers.Serializer):
email = serializers.EmailField(required=False, allow_blank=True)
password = serializers.CharField(style={'input_type': 'password'})
token = serializers.CharField(allow_blank=True, read_only=True)
一旦进入validate
功能,您可能不会得到您正在寻找的用户,pk=email
但您没有在模型中email
定义pk
。试试这个:
get_object_or_404(CustomUser, email=email)
推荐阅读
- git - 过滤(git)差异输出以仅包含与模式匹配的行
- java - jni:在 jclass 上调用对象方法
- git - AIX 7.1 中的 GIT 安装
- android - 如何从 Service Android Q 启动 Activity
- django - 如何按数字顺序查询值?
- c# - 如果它是 C# 中其他进程的用户,则无法关闭数据库连接
- php - 如何使用 Eloquent 编写此查询
- javascript - 如何在特定域和 url 的 chrome 扩展中使用代理
- python - 如何解决python错误NotADirectoryError:[Errno 20]不是目录:
- angular - 未捕获的错误:找不到模块“tslib”| 将 Angular 项目版本 10 更新到 11