Reputation: 1
I am implementing a custom user model which has user and nursery accounts. The registration is happening but login is not happening as I expect it to behave. Also the token authentication is not working I guess something is wrong in my views.py but I'm not being able to figure it out. I'm getting this error while logging in:
AttributeError at /api/auth/login/user
Got AttributeError when attempting to get a value for field `account` on serializer `UserSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Account` instance.
Original exception text was: 'Account' object has no attribute 'account'.
Here is my models.py
class AccountManager(BaseUserManager):
def create_user(self, username, email, contact, password=None):
"""Create and return a `User` with an email, username and password."""
if username is None:
raise TypeError('Users must have a username.')
if email is None:
raise TypeError('Users must have an email address.')
user = self.model(username=username,
email=self.normalize_email(email), contact=contact)
user.set_password(password)
user.save()
return user
def create_superuser(self, username, email, contact, password):
"""
Create and return a `User` with superuser (admin) permissions.
"""
if password is None:
raise TypeError('Superusers must have a password.')
user = self.create_user(username, email, contact, password)
user.is_superuser = True
user.is_staff = True
user.save()
return user
def get_by_natural_key(self, email):
return self.get(email=email)
class Account(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(verbose_name="email", max_length=60, unique=True)
username = models.CharField(max_length=30, unique=True)
contact = models.CharField(max_length=10, unique=True, default=False)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_nursery = models.BooleanField(default=False)
is_user = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'contact']
objects = AccountManager()
def get_username(self):
return (self.username)
def __str__(self):
return self.email
class User(Account, models.Model):
account = models.OneToOneField(
Account, on_delete=models.CASCADE, primary_key=True)
full_name = models.CharField(max_length=30)
address = models.CharField(max_length=256)
class Nursery(Account, models.Model):
account = models.OneToOneField(
Account, on_delete=models.CASCADE, primary_key=True)
nursery_name = models.CharField(max_length=30)
serializers.py
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['email', 'username', 'contact', 'password']
extra_kwargs = {'password': {'write_only': True}}
class UserSerializer(serializers.ModelSerializer):
account = AccountSerializer(many=False)
class Meta:
model = User
fields = ['account', 'full_name', 'address']
def create(self, validated_data):
account_data = validated_data.pop('account')
user = User.objects.create(**validated_data)
Account.objects.create(user=user, **account_data)
return user
class NurserySerializer(serializers.ModelSerializer):
account = AccountSerializer(many=False)
class Meta:
model = Nursery
fields = ['account', 'nursery_name']
def create(self, validated_data):
account_data = validated_data.pop('account')
nursery = Nursery.objects.create(**validated_data)
Account.objects.create(nursery=nursery, **account_data)
return nursery
class UserLoginSerializer(serializers.Serializer):
email = serializers.CharField()
password = serializers.CharField()
def validate(self, data):
account = authenticate(**data)
if account and account.is_active:
return account
raise serializers.ValidationError("Incorrect Credentials")
class NurseryLoginSerializer(serializers.Serializer):
email = serializers.CharField()
password = serializers.CharField()
def validate(self, data):
account = authenticate(**data)
if account and account.is_active:
return account
raise serializers.ValidationError("Incorrect Credentials")
views.py
from rest_framework import generics, permissions
from rest_framework.response import Response
from .serliaziers import UserSerializer, NurserySerializer, UserLoginSerializer, NurseryLoginSerializer, AccountSerializer
class RegisterUserAPI(generics.GenericAPIView):
serializer_class = UserSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
return Response({
"user": UserSerializer(user, context=self.get_serializer_context()).data,
})
class RegisterNurseryAPI(generics.GenericAPIView):
serializer_class = NurserySerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
nursery = serializer.save()
return Response({
"nursery": NurserySerializer(nursery, context=self.get_serializer_context()).data,
})
class LoginUserAPI(generics.GenericAPIView):
serializer_class = UserLoginSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
account = serializer.validated_data
return Response({
"user": UserSerializer(account, context=self.get_serializer_context()).data,
})
class LoginNurseryAPI(generics.GenericAPIView):
serializer_class = NurseryLoginSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
nursery = serializer.validated_data
return Response({
"user": NurserySerializer(nursery, context=self.get_serializer_context()).data,
})
urls.py
from django.urls import path, include
from .api import RegisterUserAPI, RegisterNurseryAPI, LoginNurseryAPI, LoginUserAPI
urlpatterns = [
path('api/auth/register/user', RegisterUserAPI.as_view()),
path('api/auth/register/nursery', RegisterNurseryAPI.as_view()),
path('api/auth/login/nursery', LoginNurseryAPI.as_view()),
path('api/auth/login/user', LoginUserAPI.as_view())
]
Upvotes: 0
Views: 915
Reputation: 1309
Try something like this
class UserLoginView(ObtainAuthToken):
def post(self, request, **kwargs):
serializer = self.serializer_class(data=request.data,
context={
'request':request
})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response(
{
'token':token.key,
'username':user.username,
}
)
UserLoginView inherits from ObtainAuthToken which looks for the AUTH_USER_MODEL in your project and asks for the required parameters to ogin that user based on the user model you specified there.
I hope this helps.
edit.
To get the token while registering a user you can do something like this:
@api_view(['POST'])
@permission_classes((AllowAny,))
def api_user_registration_view(request):
if request.method == 'POST':
serializer = UserRegistrationSerializer(data=request.data)
data = {
}
if serializer.is_valid():
user = serializer.save()
data['response'] = 'New user registration succesful.'
data['email'] = user.email
data['username'] = user.username
token = Token.objects.get(user=user).key
data['token'] = token
else:
data = serializer.errors
return Response(data)
and after you make the request to the api and the response in succesful you make another request to the login endpoint
Upvotes: 1