Skip to main content
 首页 » 编程设计

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

2024年10月01日34虾米姐

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

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

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

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

  • 用户,当用户帐户是 创建。因此,一家餐厅可以有很多用户,他们都 应该只能访问该餐厅的信息。

  • 属于特定餐厅的 toastr 。一个餐厅可以有 许多 toastr 。

  • 属于 toastr 的食谱。一个 toastr 可以有很多不同的 食谱。

  • 食谱结果,属于食谱。可以有很多不同的 属于同一个 Recipe 的 Recipe 结果(不同的配料 尝试过等)。

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

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

无需进入我的每个模型并声明 owner = models.ForeignKey(User),有没有办法在我的 API ListView 和详细 View 中过滤它们?

目前我的 List API View 看起来像这样(简化示例):

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) 

模型看起来像这样:

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-'),) 

具体查看修改后的列表方法,目前它可以正常工作以过滤 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 

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

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

我将不胜感激我能得到的任何帮助!

请您参考如下方法:

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

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

示例如下:

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

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

class SomeModel(OwnedModel): 
    """ 
    This class already has the owner field 
    """ 

这种方法的一个很大的缺点是您仍然需要一个会改变每个相关表的迁移。

如果您不被允许这样做,您可以使用一种松散的、非关系的方法来做到这一点,例如 django's permission model .您可以分配自动生成的权限字符串,例如:myapp.mymodel.pkey:

最后一个替代方案是为您处理事情的第三方源应用程序:django-guardian