如何使用Django Rest Framework viewset按父对象的属性筛选嵌套数据

如何使用Django Rest Framework viewset按父对象的属性筛选嵌套数据,django,permissions,django-rest-framework,nested,Django,Permissions,Django Rest Framework,Nested,我有嵌套的数据;列表包含许多项。为了安全起见,我根据当前用户是否创建了列表以及列表是否为公共列表来筛选列表。我希望对项目也这样做,这样项目只能由经过身份验证的用户更新,但如果列表是公共的,任何人都可以查看 这是我的视图集代码,改编自工作正常的列表视图集代码。这当然不适用于项目,因为项目没有“created_by”或“is_public”属性,这些属性是父列表的属性 有没有办法用列表属性替换“created_by”和“Is_public”?i、 e.我是否可以在项的get_queryset方法中获

我有嵌套的数据;列表包含许多项。为了安全起见,我根据当前用户是否创建了列表以及列表是否为公共列表来筛选列表。我希望对项目也这样做,这样项目只能由经过身份验证的用户更新,但如果列表是公共的,任何人都可以查看

这是我的视图集代码,改编自工作正常的列表视图集代码。这当然不适用于项目,因为项目没有“created_by”或“is_public”属性,这些属性是父列表的属性

有没有办法用列表属性替换“created_by”和“Is_public”?i、 e.我是否可以在项的get_queryset方法中获取父列表对象,并检查其属性

另一种选择是,我也将“created_by”和“is_public”分配给该项,但我不希望这样做,因为它是重复的数据。列表的属性应控制项目的权限

class ItemViewSet(viewsets.ModelViewSet):
    permission_classes = [permissions.AllowAny, ]
    model = Item
    serializer_class = ItemSerializer

    def get_queryset(self):
        # restrict any method that can alter a record
        restricted_methods = ['POST', 'PUT', 'PATCH', 'DELETE']
        if self.request.method in restricted_methods:
            # if you are not logged in you cannot modify any list
            if not self.request.user.is_authenticated:
              return Item.objects.none()

            # you can only modify your own lists
            # only a logged-in user can create a list and view the returned data
            return Item.objects.filter(created_by=self.request.user)

        # GET method (view item) is available to owner and for items in public lists
        if self.request.method == 'GET':
          if not self.request.user.is_authenticated:
            return Item.objects.filter(is_public__exact=True)

          return Item.objects.filter(Q(created_by=self.request.user) | Q(is_public__exact=True))

        # explicitly refuse any non-handled methods
        return Item.objects.none()
非常感谢您的帮助

编辑:在卢卡斯·韦恩的回答和我想我现在已经把这个问题解决了。下面是我在api.py中的工作代码:

from rest_framework import viewsets, permissions
from .models import List, Item
from .serializers import ListSerializer, ItemSerializer
from django.db.models import Q


class IsOwnerOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        # handle permissions based on method
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        if hasattr(obj, 'created_by'):
            return obj.created_by == request.user

        if hasattr(obj, 'list'):
            if hasattr(obj.list, 'created_by'):
                return obj.list.created_by == request.user

class ListViewSet(viewsets.ModelViewSet):
    permission_classes = [IsOwnerOrReadOnly]
    model = List
    serializer_class = ListSerializer

    def get_queryset(self):
        # can view public lists and lists the user created
        if self.request.user.is_authenticated:
            return List.objects.filter(
                Q(created_by=self.request.user) | 
                Q(is_public=True)
            )

        return List.objects.filter(is_public=True)

    def pre_save(self, obj):
        obj.created_by = self.request.user

class ItemViewSet(viewsets.ModelViewSet):
    permission_classes = [IsOwnerOrReadOnly]
    model = Item
    serializer_class = ItemSerializer

    def get_queryset(self):
        # can view items belonging to public lists and lists the usesr created
        if self.request.user.is_authenticated:
            return Item.objects.filter(
                Q(list__created_by=self.request.user) | 
                Q(list__is_public=True)
            )

        return Item.objects.filter(list__is_public=True)
Django允许。您可以跨列表属性筛选项对象,只需跨模型使用相关字段的字段名,用双下划线分隔,直到找到所需的字段

class ItemViewSet(viewsets.ModelViewSet):
    permission_classes = [IsOwnerOrReadyOnly]
    serializer_class = ItemSerializer

    def get_queryset(self):
        if self.request.user.is_authenticated
            return Item.objects.filter(
                Q(list__created_by=self.request.user) | 
                Q(list__is_public__exact=True)
            )

        return Item.objects.filter(list__is_public=True)
要允许项目仅由其所有者更新,请编写一个


谢谢,这太棒了,我想我已经找到了缺失的部分来完成答案-父项在权限定义中作为obj.list提供。有关完整的工作代码,请参见我编辑的问题。
class IsOwnerOrReadOnly(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Instance must have an attribute named `created_by`.
        return obj.list.created_by == request.user