Django视图中的重复代码:如何避免重复?

时间:2019-06-20 08:49:04

标签: python django

对于我的很多(但不是全部)视图,我必须进行一些验证,以确保登录的用户有权访问他们尝试访问的对象。对于30多个视图,我有以下代码:

def whatever_view_name(request, id, access_id):
    check = Access.objects.filter(user=request.user, id=access_id)
    if check:
        access_object = check[0]
    else:
        return redirect(reverse("create_new_access_object"))

    .... and now my view-specific code will follow ...

因此,我需要检查该特定用户是否存在特定数据库记录(访问)。这段代码被重复了很多,似乎不正确。我一直在考虑使用中间件,但是有两个问题:a)我需要在视图中使用此对象(请参见变量access_object,所以我担心如果将其放入,则必须对其进行两次查询中间件),并且b)我始终不需要这样做,所以我想知道如何仅针对某些视图运行它,如果这是中间件,则不是全部运行。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

我能想到的一种方法是使用继承。我们可以将常见的内容重构为一个超级视图类,然后在子视图类中进行扩展。

类似这样的东西:

我们可以有一个这样的超类

class AccessVerifiedView(View):
     def get(self, request, *args, **kwargs):
        check = Access.objects.filter(user=request.user, id=kwargs["access_id"])
        if check:
            access_object = check[0]
            self.verified_get(access_object)
        else:
            return redirect(reverse("create_new_access_object"))

    def verified_get(self, access_object):
        raise NotImplementedError

然后我们可以在我们的视图中扩展该类及其用途。

class MyView(AccessVerifiedView):
    def verified_get(self, access_object):
        return access_object

这种方法更具可读性。看到代码的任何人都可以看到超类并了解代码流。

其他几种方法是

  1. 装饰器:我们可以有一个装饰器,它可以做同样的事情。然后我们可以装饰要验证的视图。

答案 1 :(得分:2)

您可以为此编写装饰器:

from functools import wraps

def check_access(function):
  @wraps(function)
  def wrap(request, id, access_id, *args, **kwargs):
        check = Access.objects.filter(user=request.user, id=access_id)
        if check.exists():
             return function(request, id, access_id, *args, **kwargs)
        else:
            return redirect(reverse("create_new_access_object"))
  return wrap

# usage

@check_access
def whatever_view_name(request, id, access_id):
     return ...