'Alternative for StringRelatedField

I am trying to get following user with their names instead of PrimaryKey, I tried to use StringRelatedField. It worked for GET request, but it does not allow to write. Could not find any alternatives for this. I want to get json result as this:

{
    "id": 1,
    "user": "admin",
    "following": "user_1"
}

I assume instead of using StringRelatedField I should redefine create in serializers, am I right?

enter image description here enter image description here

model.py

class Follow(models.Model):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name='follower'
    )
    following = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name='following'
    )

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['user', 'following'],
                name='unique_user_following'
            )
        ]

    def __str__(self) -> str:
        return self.following

serializer.py

class FollowSerializer(serializers.ModelSerializer):
    user = serializers.SlugField(
        read_only=True,
        default=serializers.CurrentUserDefault()
    )
    # following = serializers.StringRelatedField()

    class Meta:
        model = Follow
        fields = ('id', 'user', 'following',)

        validators = [
            serializers.UniqueTogetherValidator(
                queryset=Follow.objects.all(),
                fields=('user', 'following',)
            )
        ]

    def validate_following(self, value):
        if value == self.context.get('request').user:
            raise serializers.ValidationError(
                'You can not follow yourslef!'
            )
        return value

views.py

class FollowViewSet(viewsets.ModelViewSet):
    serializer_class = FollowSerializer

    def get_queryset(self):
        new_queryset = Follow.objects.filter(user=self.request.user)
        return new_queryset

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)


Solution 1:[1]

A SlugRelatedField allows to also perform a lookup when writing and thus retrieve in this case the user with the given username.

You thus can implement this as:

from django.contrib.auth import get_user_model

class FollowSerializer(serializers.ModelSerializer):
    user = serializers.SlugField(
        read_only=True,
        default=serializers.CurrentUserDefault()
    )
    following = serializers.SlugRelatedField(
        slug_field='username',
        queryset=get_user_model().objects.all()
    )

    class Meta:
        model = Follow
        fields = ('id', 'user', 'following',)
        # …
    
    # …

Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Willem Van Onsem