Estoy trabajando en la creación de permisos para una API creada con Django REST Framework. Digamos que tengo los siguientes modelos:
from django.db import models class Study(models.Model): pass class Result(models.Model): study = models.ForeignKey(Study) value = models.IntegerField(null=False) Tengo serializadores básicos y vistas para ambos modelos. Usaré permisos por objeto para otorgar a los usuarios acceso a uno o más estudios. Quiero que los usuarios solo puedan ver los Result de un Study para el que tengan permisos. Hay dos formas en las que puedo pensar para hacer esto, y ninguna parece ideal:
Result s sincronizados con Study . Esto no es un comienzo, ya que queremos que el Study sea siempre la fuente de la verdad.Study relacionado cuando un usuario intente acceder a un Result . En realidad, esto no es tan malo, pero no pude encontrar ejemplos de otros que lo hicieran de esta manera y me hizo pensar que podría estar pensando en esto fundamentalmente mal.¿Hay soluciones existentes para esto por ahí? ¿O es una clase de permisos personalizados el camino a seguir? Si es así, ¿tiene ejemplos de otros que hayan implementado de esta manera?
Como indicó, puede crear un permiso personalizado de la segunda manera: e incluir el permiso en su vista:
Estoy considerando su modelo de estudio con algún curso de parámetro, basado en eso, estoy escribiendo la solución que puede considerar para cualquier elemento en el modelo de estudio.
modelos.py
from django.db import models class Study(models.Model): course = models.CharField(max_length=50) class Result(models.Model): study = models.ForeignKey(Study) value = models.IntegerField(null=False)En permiso.py
from rest_framework import permissions class ResultOrReadOnly(permissions.BasePermission): def has_object_permission(self, request, view, obj): if request.method in permissions.SAFE_METHODS and obj.study.course == request.GET.get('course') : # read only requests return True else: # other requests such as post, patch, put return obj.study == request.GET.get('course')e incluir,
class ReviewDetail(viewsets.ViewSet): permission_classes =[ResultOrReadOnly]Y en urls.py,
Modifíquelo para aceptar el curso de parámetro de URL
Crearía un nuevo campo llamado enrolled_users en el modelo de Study para indicar qué usuario tiene acceso al objeto de Study en particular.
from django.db import models from django.conf import settings class Study(models.Model): enrolled_users = models.ManyToManyField( settings.AUTH_USER_MODEL, related_name="studies" ) # other fields class Result(models.Model): study = models.ForeignKey(Study) value = models.IntegerField(null=False)Entonces, será muy fácil en DRF filtrar el conjunto de consultas en las vistas
# views.py from .models import Study, Result from rest_framework.permissions import IsAuthenticated class StudyModelViewSet(viewsets.ModelViewSet): permission_classes = (IsAuthenticated,) def get_queryset(self): return Study.objects.filter(enrolled_users=self.request.user) class ResultModelViewSet(viewsets.ModelViewSet): permission_classes = (IsAuthenticated,) def get_queryset(self): return Result.objects.filter(study__enrolled_users=self.request.user)ModelViewSet , pero puede usar cualquier vista, pero el filtro juega el papel.