I am trying to write a login view in django restframe work to authenticate a user into the application but each time I send a request to the server I keep getting this error
`{ 'email': ['email already exist'] }``
here is how I wrote my login serializer
class UserLoginSerializer(serializers.ModelSerializer):
full_name: str = serializers.CharField(source='get_name', read_only=True)
tokens: str = serializers.CharField(source='get_token', read_only=True)
class Meta:
model = User
fields = (
'id',
'full_name',
'email',
'password',
'is_superuser',
'is_seller',
'created_at',
'profile_pic',
'tokens'
)
extra_kwargs = {
'password' : {'write_only':True, 'required': True},
'id': {'read_only': True},
'is_superuser': {'read_only': True},
'is_seller': {'read_only': True},
'created_at': {'read_only': True},
'profile_pic': {'read_only': True}
}
def validate(self, data: dict) -> dict:
email: str = data.get('email', '')
password: str = data.get('password', '')
print(password, email)
user: auth = auth.authenticate(email=email, password=password)
print(user)
data = {
'email': user.email,
'tokens': user.get_token()
}
return data
and here is how I wrote my loginapiview
class UserLoginAPIView(generics.GenericAPIView):
serializer_class = UserLoginSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
return Response(serializer.data, status=status.HTTP_200_OK)
My assumption is it is because you are using a ModelSerializer
, so the built in email validator is checking as if it's a create call
This is my Email User Serializer, shamelessly ripped and edited from rest_framework.authtoken.serializers.AuthTokenSerializer.
It's slightly different from yours as it's returning user
in validated_data instead of returning it directly from the validate function, so there's a bit extra inside the view.
from django.contrib.auth import authenticate
from rest_framework import serializers
from django.utils.translation import gettext_lazy as _
class EmailUserLoginSerializer(serializers.Serializer):
"""Email login"""
email = serializers.CharField(label=_("email"), write_only=True)
password = serializers.CharField(
label=_("Password"),
style={"input_type": "password"},
trim_whitespace=False,
write_only=True,
)
token = serializers.CharField(label=_("Token"), read_only=True)
def validate(self, attrs):
"""Validate"""
email = attrs.get("email")
password = attrs.get("password")
if email and password:
user = authenticate(
request=self.context.get("request"),
email=email,
password=password,
)
# The authenticate call simply returns None for is_active=False
# users. (Assuming the default ModelBackend authentication
# backend.)
if not user:
msg = _("Unable to log in with provided credentials.")
raise serializers.ValidationError(msg, code="authorization")
else:
msg = _('Must include "email" and "password".')
raise serializers.ValidationError(msg, code="authorization")
attrs["user"] = user
return attrs
class UserLoginAPIView(generics.GenericAPIView):
serializer_class = EmailUserLoginSerializer
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data["user"]
# Note: No need for status=status.HTTP_200_OK as that's the default!
return Response({
"email": user.email,
"tokens": user.get_token(),
})