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)