Django REST框架:按当前登录的所有者过滤嵌套对象

时间:2017-07-12 17:15:30

标签: django django-rest-framework

我正在尝试通过当前授权用户的所有权来过滤API响应中的嵌套对象。

这是我的设置: Django 1.8,Django REST框架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')

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

不同的用户可以为同一个Container创建Notification对象。

如果我取消注释#notifications_for_container = NotificationSerializer(many = True),我会得到:

"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 ",
        },
      ]
     }
    ]

无论我当前登录的是哪个用户。

我在此尝试实现的目标是仅在API响应的notifications_for_container部分中返回所有者的通知。

例如,如果我以pk=2用户身份登录,我应该只获得

"data": [
    {
      "notifications_for_container": [
        {
          "pk": 11,
          "owner": 2,
        }
      ]
...
...

我一直在尝试从How can I apply a filter to a nested resource in Django REST framework?实施解决方案,但我得到KeyError at /api/containers/ 'request'

我已经尝试解决这个问题2天了,也许我没有看到明显的东西,所以任何帮助都会受到赞赏。 提前谢谢!

2 个答案:

答案 0 :(得分:0)

您的代码的问题似乎是context属性没有填充当前请求。看看Including extra context。可能你应该做的事情如下:

     serializer = ContainerSerializer(many=True, context={'request': request})

答案 1 :(得分:0)

第一

serializer = ContainerSerializer(many=True, context={'request': request})

serializer = ContainerSerializer(many=True, context=self.get_serializer_context())

第二

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