如何在不显式声明所有模型上的所有者字段的情况下分配 Django 对象所有权?

Mor*_*ran 5 python django django-models django-rest-framework

我目前正在尝试找出 Django 网站 API 的每个用户对象权限。

我有几个包含敏感信息的模型,我需要能够根据用户进行过滤。

对于其中一个模型的简化示例:

  • 餐厅,网站的主要客户。

  • 用户,创建用户帐户时,每个用户都会被分配一家餐厅。因此,一家餐厅可以拥有许多用户,并且他们都只能访问该餐厅的信息。

  • 烤箱,属于特定餐厅。一家餐厅可以有很多烤箱。

  • 食谱,属于烤箱。烤箱可以有许多不同的食谱。

  • 配方结果,属于配方。同一配方可能有许多不同的配方结果(尝试了不同的成分等)。

至少有 12+ 种不同的型号。特定餐厅的所有模型都必须对其他餐厅隐藏,毕竟我们不希望他们能够查看其他餐厅的食谱!

并非所有模型都有 user = models.ForeignKey(User)

无需进入我的每个模型并声明owner = models.ForeignKey(User),是否有一种方法可以在我的API列表视图和详细信息视图中过滤它们?

目前我的列表 API 视图如下所示(简化示例):

class RecipeResultsListAPIView(ListAPIView):
    queryset = RecipeResults.objects.all()
    queryset = queryset.prefetch_related('oven')
    serializer_class = RecipeResultsListSerializer 
    filter_backends = (DjangoFilterBackend,)
    filter_fields = ('id', 'time', 'oven', 'recipe_name', 'recipe_description')
    pagination_class = ExpertPageNumberPagination

    def list(self, request):
       user = User.objects.get(username=request.user)
       restaurant = Restaurant.objects.get(user=user)
       ovens = Oven.objects.filter(restaurant=restaurant)
       queryset = RecipeResults.objects.filter(oven__in=ovens)
       serializer = RecipeResultsListSerializer(queryset, many=True, context={'request':request})
       return Response(serializer.data)
Run Code Online (Sandbox Code Playgroud)

其模型如下所示:

class RecipeResults(models.Model):
    time = models.DateTimeField()
    oven = models.ForeignKey(Oven, on_delete=models.CASCADE)
    recipe_name = models.CharField(max_length=20)
    recipe_description = models.CharField(max_length=50)

    def __str__(self):
        return str(self.time) + ': ' + self.recipe_name + ' = ' + self.recipe_description

    def __key(self):
        return self.oven, self.time, self.recipe_name

    def __eq__(self, y):
        return isinstance(y, self.__class__) and self.__key() == y.__key()

    def __hash__(self):
        return hash(self.__key())

    class Meta:
        unique_together=(('time','recipe_name', 'oven-'),)
Run Code Online (Sandbox Code Playgroud)

具体来说,查看修改后的列表方法,目前该方法可以正常过滤 API 调用结果,仅显示属于登录用户的配方结果。

我想要弄清楚是否有更简单的方法来做到这一点,对于每个模型,我都必须追溯到特定餐厅的所有权,这很快就会变得混乱,因为我有 12 个以上不同的模型。

我不确定在每个模型上声明“owner = models.ForeignKey(User)”是否是正确的方法。感觉检索数据时会创建许多额外的步骤。

我也尝试过

class IsOwnerOrAdmin(BasePermission):
    """
    Custom permission to only allow owners of an object to see and edit it.
    Admin users however have access to all.
    """
    def has_object_permission(self, request, view, obj):
        # Permissions are only allowed to the owner of the snippet
        if request.user.is_staff:
            return True
        return obj.user == request.user
Run Code Online (Sandbox Code Playgroud)

但这似乎没有正确过滤,而且并非所有模型都分配有用户字段。

请记住,我是一名初级开发人员,我在工作中学到了很多东西。我只在公司的 API 方面工作。网站和模式已经是一项正在进行的工作,其他系统依赖于它,所以我试图不要过多地修改模式或模型(如果可能的话,我想避免这种情况,但如果这是唯一的,我会这样做方式)。最初我也只是为了 API 工作而被带进来的。公司知道我是一名初级开发人员,我非常感谢在学习这个项目的同时获得了成长的机会,但是这个问题似乎给我带来了比实际构建 API 的其余部分更多的麻烦。网站。

我将非常感谢我能得到的任何帮助!

Alv*_*aro 6

我认为在这种情况下您可能会从模型继承中受益。

您可以为受所有者影响的对象定义基本模型。

一个例子可以是这样的:

class OwnedModel(models.Model):
    owner = models.ForeignKey(User)

    class Meta:
        abstract = True
Run Code Online (Sandbox Code Playgroud)

然后您可以简单地将其添加为其他模型的基础:

class SomeModel(OwnedModel):
    """
    This class already has the owner field
    """
Run Code Online (Sandbox Code Playgroud)

这种方法的一个很大的缺点是您仍然需要进行迁移来更改每个涉及的表。

如果不允许您这样做,您也许可以使用松散的非关系方法来完成,例如使用django 的权限模型。您可以分配自动生成的权限字符串,例如myapp.mymodel.pkey

最后一个选择是这个第三方源应用程序,它可以为您处理事情:django-guardian