Nimra Aziz
Nimra Aziz

Reputation: 35

How to set serializer custom field in create method of Model Serializer?

I'm working with a very simple model, but i'm stuck here. I just want the after creating a User, i sent him a Token. i created a custome serializer field. here is my Serializer class.

class UserCreateSerializer(serializers.ModelSerializer):
    token = serializers.CharField(allow_blank=True, read_only=True)
    password = serializers.CharField(min_length=8, write_only=True)
    class Meta:
        model = get_user_model()
        fields = ('id',
                  'username',
                  'password',
                  'token',
                  )

    def create(self, validated_data):
        uname = validated_data['username']
        password = validated_data['password']
        user = get_user_model().objects.create(
            username=uname,
        )
        user.set_password(password)
        user.save()

        data = self.get_initial()
        data['token'] = Token.objects.create(user=user)

        return user

here is my CreateAPIView

class UserCreateAPIView(CreateAPIView):
    serializer_class = UserCreateSerializer
    permission_classes = [AllowAny]

every time when i POST a request to it, it doesn't response me with token, it always gives response without token.

{
    "id": 41,
    "username": "J.Son",
}

Upvotes: 3

Views: 1220

Answers (1)

JPG
JPG

Reputation: 88689

from the source code of Token model, it's defined as

class Token(models.Model):
        """
        The default authorization token model.
        """
        key = models.CharField(_("Key"), max_length=40, primary_key=True)
        user = models.OneToOneField(
            settings.AUTH_USER_MODEL, related_name='auth_token',
            on_delete=models.CASCADE, verbose_name=_("User")
        )
        created = models.DateTimeField(_("Created"), auto_now_add=True)

hence, user_instance.auth_token.key will return the corresponding KEY.

According to serializer, you can do that by reffering with source argument as,

class UserCreateSerializer(serializers.ModelSerializer):
    token = serializers.CharField(
        allow_blank=True, read_only=True, source='auth_token.key')
    # your code


    def create(self, validated_data):
        # your code
        user.refresh_from_db()
        return user


UPDATE
Why refresh_from_db()?
In your create() method, first you are creating theUser object and assigns to user variable. At that time user.auth_token.key will be None, because, no Token is created yet. Then you are creating a Token corresponding to the User. But, It will not reflect on user variable (no auto-refresh functionality there). Hence still user.auth_token.key will be None. This same user object/instance is used in to_representation method to represent the final data. That's why initially it's didn't showed the Token.

The refresh_from_db() , as the name suggests it refreshes it's values from DB, hence it's got user.auth_token.key.

Upvotes: 1

Related Questions