Reputation: 17
I'm trying to filter nested objects in API response by the ownership of currently authorized user.
Here is my setup: Django 1.8, Django REST framework 3.
class Container(models.Model):
container_title = models.CharField(max_length = 50)
class Item(models.Model):
item_title = models.CharField(max_length = 50, blank = True, null = True, default = " ")
item_container = models.ForeignKey(Container, on_delete = models.CASCADE, related_name = 'all_items_in_container')
class Notification(models.Model):
owner = models.ForeignKey('auth.User', null = True, on_delete = models.CASCADE)
item_to_track = models.ForeignKey(Container, default = False, blank = True, null = True, on_delete = models.CASCADE, related_name = 'notifications_for_container')
class ItemsSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Item
fields = ('pk', 'item_title')
class NotificationSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.IntegerField(source='owner.pk')
class Meta:
model = Notification
fields = ('pk', 'owner')
class ContainerSerializer(serializers.ModelSerializer):
all_items_in_container = ItemsSerializer(many=True)
#notifications_for_container = NotificationSerializer(many = True) # this line returns all existing notifications per Container
notifications_for_container = serializers.SerializerMethodField('get_current_user_notifications')
def get_current_user_notifications(self, obj):
user = self.context['request'].user
user_notifications = Notification.objects.filter(item_to_track=obj, owner=user)
serializer = NotificationSerializer(user_notifications)
return serializer.data
class Meta:
model = Container
fields = ('notifications_for_container', 'pk', 'container_title', 'all_items_in_container')
class ContainerViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Container.objects.all()
def list(self, request, *args, **kwargs):
queryset = self.queryset
serializer = ContainerSerializer(data = [], many = True, context={'request': request})
if serializer.is_valid():
new_serializer = ContainerSerializer(queryset, many = True, context={'request': request})
data = new_serializer.data[:]
return Response({'data':data})
def retrieve(self, request, pk, *args, **kwargs):
queryset = self.get_queryset()
try:
holder = Container.objects.get(pk=pk)
except Container.DoesNotExist:
holder = False
if holder:
serializer = ContainerSerializer(holder, context={'request': request})
data = serializer.data
return Response({'data':data})
Different users can create Notification objects for the same Container.
If i uncomment #notifications_for_container = NotificationSerializer(many = True)
, I'll get:
"data": [
{
"notifications_for_container": [
{
"pk": 11,
"owner": 2,
},
{
"pk": 20,
"owner": 46,
}
],
"pk": 6,
"container_title": "TEST CONTAINER",
"all_items_in_holder": [
{
"pk": 12,
"item_title": "xbox1 from amazon ",
},
]
}
]
no matter under which user I'm currently logged in.
What I'm trying to achieve here, is to return only owner's Notification in notifications_for_container
section of API response.
Eg if I'm logged in as user with pk=2
, I should get only
"data": [
{
"notifications_for_container": [
{
"pk": 11,
"owner": 2,
}
]
...
...
I've been trying to implement the solution from How can I apply a filter to a nested resource in Django REST framework?, but I'm getting KeyError at /api/containers/ 'request'
I've been trying to solve this problem for 2 days already and maybe I don't see something obvious, so any help would be appreciated. Thanks in advance!
Upvotes: 0
Views: 1519
Reputation: 7717
first:
serializer = ContainerSerializer(many=True, context={'request': request})
or
serializer = ContainerSerializer(many=True, context=self.get_serializer_context())
second:
def get_current_user_notifications(self, obj):
user = self.context['request'].user
# user_notifications is a queryset
user_notifications = Notification.objects.filter(item_to_track=obj, owner=user)
# so you need add many=True
serializer = NotificationSerializer(user_notifications, many=True)
return serializer.data
Upvotes: 1
Reputation: 77329
The problem with your code seems to be that the context
attribute is not being populated with the current request. Take a look at Including extra context. Probably you should be doing something like:
serializer = ContainerSerializer(many=True, context={'request': request})
Upvotes: 0