I have User
s and Group
s, where Group
s are a PrimaryKeyRelatedField
on User
s. When writing a User
, I only want to assign it to Group
s the current user is in. When retrieving a User
, I only want to show the Group
s that it has in common with the current user.
For example, suppose user_1
belongs to group_1
, and user_2
belongs to group_2
. If user_1
pings my LIST USERS
endpoint I want to get:
[{'groups': [1], 'username': 'user_1'}, {'groups': [], 'username': 'user_2'}]
Note that although group_2
exists, it is not listed under user_2
's groups, because user_1
is not in it.
Thoughts so far:
- Overloading
to_representation
seems like it will just change how the group is shown in the list of groups, not whether it is shown at all - There are some guides about how to filter the writable
group
choices here, meaning thatuser_1
couldn't, for instance, add itself togroup_2
- There are some guides about how to filter for a read-only field
- I could combine the above two and do a read-only field and a write-only field, as suggested here for a different problem, but I'd rather not.
I don't see any guides on how have a single read/write RelatedField
filtered by the current user. Any ideas?
My code:
# serializers.py, vanilla
from django.contrib.auth.models import User, Group
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('username', 'groups')
# views.py
from django.contrib.auth.models import User
from rest_framework.authentication import BasicAuthentication
from rest_framework import viewsets
from app import serializers
class UserViewSet(viewsets.ModelViewSet):
serializer_class = serializers.UserSerializer
queryset = User.objects.all()
authentication_classes = (BasicAuthentication,)
# serializers.py, with write-choice filter modification
class FilteredRelatedField(serializers.PrimaryKeyRelatedField):
def get_queryset(self):
user = self.context['request'].user
user_groups = user.groups.values_list('id', flat=True)
queryset = Group.objects.filter(id__in=user_groups)
return queryset
class UserSerializer(serializers.ModelSerializer):
groups = FilteredRelatedField(many=True)
class Meta:
model = User
fields = ('username', 'groups')
# serializers.py, with read-only filtering
class UserSerializer(serializers.ModelSerializer):
groups = serializers.SerializerMethodField()
class Meta:
model = User
fields = ('username', 'groups')
def get_groups(self, instance):
instance_user_groups = instance.groups.values_list('id', flat=True)
current_user_groups = self.context['request'].user.groups.values_list('id', flat=True)
return [x for x in instance_user_groups if x in current_user_groups]