【问题标题】:Enforcing permissions through a related model in Django Rest Framework通过 Django Rest Framework 中的相关模型强制执行权限
【发布时间】:2021-12-13 04:02:11
【问题描述】:

我正在为使用 Django REST 框架构建的 API 构建权限。假设我有以下模型:

from django.db import models

class Study(models.Model):
   pass

class Result(models.Model):
   study = models.ForeignKey(Study)
   value = models.IntegerField(null=False)

我对这两个模型都有基本的序列化程序和视图。我将使用每个对象的权限来授予用户访问一项或多项研究的权限。我希望用户只能查看Results 以获得他们有权访问的Study。我可以想到两种方法来做到这一点,但似乎都不理想:

  1. 保持Results 上的每个对象权限与Study 同步。这只是一个非首发,因为我们希望 Study 始终是真相的来源。
  2. 编写一个自定义权限类,当用户尝试访问Result 时检查相关Study 的权限。这实际上并不算太糟糕,但我找不到其他人这样做的例子,这让我觉得我可能在考虑这个根本错误。

是否有针对此问题的现有解决方案?或者自定义权限类是要走的路?如果是这样,您是否有其他实施这种方式的示例?

【问题讨论】:

  • querysetA = Study objects 允许用户(基本上是一个值列表,即 id);那么最终的queryset = Result.objects.filter(study__in = querysetA)

标签: django django-rest-framework


【解决方案1】:

正如您所说,您可以按照第二种方式进行自定义权限: 并在您的视图中包含权限:

我正在考虑您的学习模型和一些参数课程,基于此,我正在编写您可以为学习模型中的任何元素考虑的解决方案

models.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)

在权限.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')

并包括,

class ReviewDetail(viewsets.ViewSet):

     permission_classes =[ResultOrReadOnly]

在 urls.py 中,

修改它以接受URL参数课程

【讨论】:

    【解决方案2】:

    我将在 Study 模型中创建一个名为 enrolled_users 的新字段,以指示哪些所有用户都可以访问特定Study 对象。

    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)

    然后,在 DRF 中很容易过滤视图中的查询集

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

    注意事项

    • 这也将处理对象权限(详细视图)请求
    • 这不会返回 HTTP 403 的状态码,而是 HTTP 404
    • 这里我使用了 ModelViewSet 类,但是,您可以使用任何视图,但过滤器会起作用。

    【讨论】:

      猜你喜欢
      • 2018-11-11
      • 2016-06-23
      • 1970-01-01
      • 1970-01-01
      • 2016-06-17
      • 1970-01-01
      • 2022-09-23
      • 1970-01-01
      • 2021-02-14
      相关资源
      最近更新 更多