Mohsen Amiri
Mohsen Amiri

Reputation: 175

how to add more attributes to what an api returns

I am trying to write an API using django rest framework in which, you give a username and a password and in return you get an AuthToken or in other words you login. now I want this API to also return some fields like the email of the user along with the AuthToken. so if the authentication was successful, the get an authToken and the user's email. Can anyone help me on how I could be able to do this by adding or changing a bit of my code?

These are my models:

class UserManager(BaseUserManager):
    def createUser(self, email, password=None, **extra_fields):
        if not email:
            raise ValueError('Email Not Found!!!')
        user = self.model(email=self.normalize_email(email), **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def createSuperUser(self, email, password):
        user = self.createUser(email, password)
        user.isAdmin = True
        user.isSuperUser = True
        user.save(using=self._db)
        return user


class User(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=100, unique=True, validators=[RegexValidator(regex="^(?=[a-z0-9._]{5,20}$)(?!.*[_.]{2})[^_.].*[^_.]$")])
    email= models.EmailField(max_length=100, unique=True,  validators=[EmailValidator()])
    name = models.CharField(max_length=100)
    isSuspended = models.BooleanField(default=False)
    isAdmin = models.BooleanField(default=False)
    emailActivation = models.BooleanField(default=False)
    balance = models.IntegerField(default=0)

    objects = UserManager()

    USERNAME_FIELD = 'username'

These are my serializers:

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = get_user_model()
        fields = ('username','email', 'password', 'name')
        extra_kwargs = {'password': {'write_only': True, 'min_length': 8}}

    def create(self, validated_data):
        return get_user_model().objects.createUser(**validated_data)

    def update(self, instance, validated_data):
        password = validated_data.pop('password', None)
        user = super().update(instance, validated_data)

        if password:
            user.set_password(password)
            user.save()

        return user


class AuthTokenSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField(trim_whitespace=False)

    def validate(self, attrs):
        username = attrs.get('username')
        password = attrs.get('password')

        user = authenticate(
            request=self.context.get('request'),
            username= username,
            password= password
        )
        if not user:
            msg = 'Authentication Failed.'
            raise serializers.ValidationError(msg, code='authentication')

        attrs['user'] = user
        return attrs

And finally, these are my views:

class CreateUserView(generics.CreateAPIView):
    serializer_class = UserSerializer


class CreateTokenView(ObtainAuthToken):
    serializer_class = AuthTokenSerializer
    renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES


class ManageUserView(generics.RetrieveAPIView):
    serializer_class = UserSerializer
    authentication_classes = (authentication.TokenAuthentication,)
    permission_classes = (permissions.IsAuthenticated,)

    def get_object(self):
        return self.request.user

Upvotes: 0

Views: 729

Answers (2)

Jaime Ortiz
Jaime Ortiz

Reputation: 1319

For what i understand you just want to return the toekn and the email of the user right? I used this class based view to login users using token authentication.

from rest_framework.authtoken.views import ObtainAuthToken



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,
                'email':user.email,
                
            }
        )

Upvotes: 0

K14
K14

Reputation: 181

create a new serializer inside serializer.py

from rest_framework.authtoken.models import Token as DefaultTokenModel
class TokenSerializer(serializers.ModelSerializer):
   
    user = UserSerializer()

    class Meta:
        model = DefaultTokenModel
        fields = ('key', 'user',)

add this function in views.py

def get_token_response(user):
    serializer_class = TokenSerializer
    token, _ = DefaultTokenModel.objects.get_or_create(user=user)
    serializer = serializer_class(instance=token)
    return Response(serializer.data, status=status.HTTP_200_OK)

now override post method of CreateTokenView

def post(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    user = serializer.validated_data['user']
    return get_token_response(user)

Upvotes: 0

Related Questions