user2241956
user2241956

Reputation: 17

Django REST framework: filter nested objects by currently logged in owner

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.

MODELS

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')

SERIALIZERS

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')

DRF VIEW

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

Answers (2)

Ykh
Ykh

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

Paulo Scardine
Paulo Scardine

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

Related Questions