Sebastian
Sebastian

Reputation: 1533

DRF: How to make serializer fields different depending on instance attributes

I'm not overly familiar with DRF or Django, but here goes:

I'm working on a workout-API that returns a user, and the user is able to set the visibility of their profile. The table looks something like:

id | username | email | coach_id | visibility

where visibility is one of public, coach, private.

This means that if User 1 has visibility = private, another user fetching their profile should only see the attributes id and username, but the user themselves should get all the attributes.

The user's coach should see a profile if visibility = public or visibility = coach.

I've looked into dynamically setting the serializer's fields-variable, with no luck (because the fields should be "generated" depending on the content of the object/instance).

I've also looked into extra_field = serializers.SerializerMethodField(), but that resulted in all the values being shown as sub-properties of extra_field.

What I am wondering is: What is the best way to attack this problem?

Upvotes: 1

Views: 653

Answers (1)

Sebastian
Sebastian

Reputation: 1533

I solved it!

I used the to_representation-function in my serializer like so:

class VisibilityAwareUserSerializer(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = get_user_model()
        fields = [
            "id",
            "username",
            "visibility",
            "email",
            "coach",
        ]

    def to_representation(self, instance):
        ret = super(PermissionAwareUserSerializer, self).to_representation(instance)
        fields_to_pop = [
            "email",
            "coach",
        ]
        if not self.userCanSeeObject(self.context['request'].user, instance):
            [ret.pop(field,'') for field in fields_to_pop]
        return ret

    def userCanSeeObject(self, user, obj):
        return ((obj.visibility == "public") or (obj.visibility == "coach" and obj.coach == user or obj == user) or (obj.visibility == "private" and obj == user))

Feel free to point out weaknesses in this solution, but it seems to work well for me.

Upvotes: 2

Related Questions