how to add more attributes to what an api returns

Welcome to Programming Tutorial official website. Today - we are going to cover how to solve / find the solution of this error how to add more attributes to what an api returns on this date .

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

Answer

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)