у меня есть вложенные данные; Список содержит много предметов. В целях безопасности я фильтрую списки по тому, создал ли текущий пользователь этот список и является ли он общедоступным. Я хотел бы сделать то же самое для элементов, так что элементы могут обновляться только аутентифицированными пользователями, но могут быть просмотрены кем угодно, если список общедоступен.
Вот мой код набора представлений, адаптированный из кода набора списков, который работает нормально. Это, конечно, не работает для элементов, потому что элемент не имеет свойств «create_by» или «is_public» - это свойства родительского списка.
Есть ли способ, которым я могу заменить "creat_by" и "is_public" на свойства списка? я могу получить объект родительского списка в методе get_queryset элемента и проверить его свойства?
Альтернативой является то, что я также назначаю элементу "create_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)