首页 > 解决方案 > 如何在基于函数的视图 Django 中分别添加对 GET、POST、PATCH、DELETE 的自定义权限

问题描述

我正在开发一个项目,该项目具有多种用户类型,例如管理员、协调员、副协调员,每个用户都可以在不同的部门担任不同的角色。例如。用户 A 可以是 XX 部门的协调员,然后 A 可以是 YY 部门的管理员,但他不能在同一部门担任相同的角色。

我打算为此编写自定义权限和角色。我写的是这样的:

def coordinator(request, uid):
    if request.method == 'GET':
    //some logic
    if request.method == 'POST':
    //some logic
    if request.method == 'PATCH':
    //some logic
    if request.method == 'DELETE':
    //some logic

不想做的是以下方法:

def coordiantor_delete(request, uid):
    if request.method == 'DELETE':

def coordiantor_detail(request, uid):
    if request.method == 'GET':

def coordiantor_create(request):
    if request.method == 'POST':

def coordiantor_update(request, uid):
    if request.method == 'PATCH':

有没有一种方法可以为视图函数的特定 HTTP 方法添加权限,而无需将其拆分为各种视图。因为我只想拥有一个像 /coordinator/ 和 /coordinator/id/ 这样的 API 端点,它们应该支持上述 HTTP 方法,但具有像 admin 这样的权限也可以从部门中删除协调员,而协调员自己也可以离开部门而没有其他人对 DELETE 方法具有此权限。让我知道对此有哪些可能的方法或需要进行的其他一些更改。

标签: djangodjango-modelsdjango-rest-frameworkdjango-views

解决方案


我已经编辑了我的答案,以尝试更好地满足您的需求。这不是一个完整的解决方案,我会考虑对其进行重构并根据您的需要对其进行定制。

我想到了两个解决方案,

  1. 创建一个装饰器,接受一个函数来检查某些方法的限制,并引发调用 403 模板的 PermissionDenied。
  2. 创建一个简单的函数来进行一些测试,如果测试失败,则引发 PermissionDenied。在视图函数的每个方法中调用此函数。

由于装饰器的可重用性,我更喜欢方法 1。

这是我的初始设置

from functools import wraps

from django.core.exceptions import PermissionDenied
from django.http import HttpResponse


def permission_denied_test(test_func):
    """
    Decorator for views that raises PermissionDenied if test_func fails
    The test should be a callable and returns True if the test is passed
    Your test function has access to the views request object
    """
    def decorator(view_func):
        @wraps(view_func)
        def _wrapped_view(request, *args, **kwargs):
            if test_func(request):
                return view_func(request, *args, **kwargs)
            raise PermissionDenied
        return _wrapped_view
    return decorator


def coordinator_passes_test(request):
    if request.method == 'GET':
        return True  # passed test
    elif request.method == 'POST':
        return False  # failed test


@permission_denied_test(coordinator_passes_test)
def view(request):
    if request.method == 'GET':
        return HttpResponse('Passed test, this code is reached.')
    elif request.method == 'POST':
        return HttpResponse('Failed test, this code isnt reached.')

这样你的测试是可重用的,你可以轻松地将它应用到多个视图


推荐阅读