This is my model (CustomUser):
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
I have the following serializer:
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
#################################################################################
This is the view:
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)
When I execute a POST to my api I get the following error:
%%%%%%%%%%%%%%%%%%%%%%%%%%% serializer errors %%%%%%%%%%%%%%%%%%%%%%%% {'email': [ErrorDetail(string='user with this E-mail already exists.', code='unique')]} Bad Request: /users/api/login/
It seems that Allauth has intercepted the request and validated it as a register request instead of login.
I have tried using rest-auth library and I got the same results.
Any suggestions as to how can I override Allauth I guess?
Thanks!
This is my users/urls.py file:
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')),
]
I am using Token from 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
Oh! I understood the problem. You are using ModelSerializer which serializes the data according to the model. It is because of that, the serializer is checking if the email is unique (as you defined in your model).
There are several improvements we could do to your code but in order to make it works and reach the validate
function you should change your serializer.
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)
Once inside validate
function you will probably get no users as you are looking for pk=email
but you didn't define email
as pk
in your models. Try this instead:
get_object_or_404(CustomUser, email=email)