我有嵌套数据;列表包含许多项目。为了安全起见,我通过当前用户是否创建列表以及列表是否公开来过滤列表。我想对商品执行相同的操作,以便商品只能由经过身份验证的用户更新,如果列表是公开的,则任何人都可以查看。
这是我的视图集代码,从工作正常的列表视图集代码改编而成。这当然不适用于Item,因为该项目不具有“ created_by”或“ is_public”属性-这些是父级列表的属性。
有没有办法用列表属性替换“ created_by”和“ is_public”?即可以在项目的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()
非常感谢您的帮助!
编辑:在卢卡斯·韦恩的答案和this post之间,我认为我已经对此进行了整理。这是我在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)
答案 0 :(得分:1)
Django允许lookups that span relationships。您可以在列表属性中过滤Item对象,只需在模型之间使用相关字段的字段名,并用双下划线分隔,直到找到所需的字段。
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)
要只允许项目所有者更新项目,请写一个custom object-level permission class。
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