首页 > 解决方案 > 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

标签: django-rest-frameworkdjango-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)

推荐阅读