Django-guardian 和 Django-rest-framework

6
我希望在一个restful项目(使用django-rest-framework)中使用django-guardian来管理我的对象权限。
我想要的内容如下:
- 仅允许已登录用户在拥有“add_modelname”权限时创建对象 - 当已登录用户创建对象时,设置“delete_modelname”和“change_modelname”权限。 - 仅允许已登录用户在拥有“change_modelobject”权限时编辑对象。 - 仅允许已登录用户在拥有“delete_modelobject”权限时删除对象。
我正在尝试使用以下代码来处理这些情况:
view.py
class ModelNameViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list`, `create`, `retrieve`,
    `update` and `destroy` actions.

    Additionally we also provide an extra `highlight` action.
    """
    queryset = ModelName.objects.all()
    serializer_class = ModelNameSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, ModelNamePermission)

    def create(self, request, *args, **kwargs):
        assign_perm("change_modelname", request.user, self)
        assign_perm("delete_modelname", request.user, self)
        return super().create(request, *args, **kwargs)

permissions.py

class ModelNamePermission(permissions.BasePermission):
    """
    Custom permission to only allow owners of an object to edit it.
    """

    def has_permission(self, request, view):
        if request.method in ['GET']:
            return request.user.has_perm('view_modelname')        
        if request.method in ['POST']:
            return request.user.has_perm('add_modelname')
        if request.method in ['PUT', 'PATCH']:
            return request.user.has_perm('change_modelname')
        if request.method in ['DELETE']:
            return request.user.has_perm('delete_modelname')
        return False

    def has_object_permission(self, request, view, obj):         
        if request.method in ['GET']:
            return request.user.has_perm('view_modelname', obj)        
        if request.method in ['POST']:
            return request.user.has_perm('add_modelname', obj)
        if request.method in ['PUT', 'PATCH']:
            return request.user.has_perm('change_modelname', obj)
        if request.method in ['DELETE']:
            return request.user.has_perm('delete_modelname', obj)
        return False

我遇到的第一个问题是这行代码出现了错误:

assign_perm("change_modelname", request.user, self)

错误:

error: 'ModelNameViewSet' object has no attribute '_meta'

我认为剩下的代码可能不会起作用,但至少你可以看到我想做什么。

我还没有看到任何具有这些特定情况的示例。

编辑: 另一件事是这段代码:

request.user.has_perm('view_coachingrequest')

始终返回 true。但我从未将此权限设置给我的用户(只尝试过管理员用户,可能是这个原因)。


我想做完全相同的事情。你做过吗? - BaptWaels
1个回答

2

视图集的create方法会返回一个新创建的模型实例。您试图将权限分配给视图集对象本身。您的create方法代码应该如下所示:

def create(self, request, *args, **kwargs):
    instance = super().create(request, *args, **kwargs)
    assign_perm("change_modelname", request.user, instance)
    assign_perm("delete_modelname", request.user, instance)
    return instance

这将创建模型实例并在返回之前为其分配所需的权限。请保留HTML标签。

1
DRF视图集中的create方法返回一个响应对象,而不是模型实例。代码在这里:https://github.com/encode/django-rest-framework/blob/a81e60ff390b9b6788b2cac24a01ee4dd2dcffd2/rest_framework/mixins.py#L14您是否在考虑序列化器中的create方法? - thclark
实际上,可以在序列化器或视图集的perform_create()方法中执行(后者在此答案中显示:https://stackoverflow.com/questions/41230236/set-object-level-permission-with-django-rest-framework)。 因此,您可以自行选择在哪里保留该代码。 对我来说,我认为我会在序列化器中执行它(这可能允许您编写更清晰的错误处理代码,因为对象创建和权限分配在同一位置) - thclark

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接