菊花链式Python / Django自定义装饰器

萨奇布·阿里(Saqib Ali)

菊花链式Python / Django自定义装饰器好吗?并传递与收到的不同论点?

我的许多Django视图功能都以完全相同的代码开始:

@login_required
def myView(request, myObjectID):
    try:
        myObj = MyObject.objects.get(pk=myObjectID)
    except:
        return myErrorPage(request)       

    try:
        requester = Profile.objects.get(user=request.user)
    except:
        return myErrorPage(request)

    # Do Something interesting with requester and myObj here

仅供参考,这是urls.py文件中的相应条目的样子:

url(r'^object/(?P<myObjectID>\d+)/?$', views.myView, ),

在许多不同的视图函数中重复相同的代码根本不是DRY。我想通过创建一个装饰器来对其进行改进,该装饰器将为我完成此重复性工作并使新视图功能更简洁并如下所示:

@login_required
@my_decorator
def myView(request, requester, myObj):        
    # Do Something interesting with requester and myObj here

所以这是我的问题:

  1. 这是有效的做法吗?风格好吗?注意,我将更改myView()函数的签名。这对我来说有点奇怪和冒险。但我不确定为什么
  2. 如果我使多个这样的装饰器执行某些通用功能,但每个装饰器使用与接收到的装饰器不同的参数调用包装的函数,则可以将它们以菊花链方式链接在一起吗?
  3. 如果上面的#1和#2可以,则最好的方法是向此myView的用户指示应传入的参数集(因为不再仅查看函数定义中的参数)确实有效)
Spinlok

1)是的,链接装饰器是有效的,因为其他答案已经指出。好的样式是主观的,但是我个人认为这会使您的代码更难为他人阅读。熟悉Django但不熟悉您的应用程序的人在使用您的代码时需要保持头脑中的额外上下文。我认为遵守框架约定以使您的代码尽可能可维护非常重要。

2)答案是肯定的,将不同的参数传递给包装函数在技术上是可以的,但是请考虑一个简单的代码示例,说明其工作方式:

def decorator1(func):
    def wrapper1(a1):
        a2 = "hello from decorator 1"
        func(a1, a2)
    return wrapper1

def decorator2(func):
    def wrapper2(a1, a2):
        a3 = "hello from decorator 2"
        func(a1, a2, a3)
    return wrapper2

@decorator1
@decorator2
def my_func(a1, a2, a3):
    print a1, a2, a3

my_func("who's there?")

# Prints:
# who's there?
# hello from decorator 1
# hello from decorator2

在我看来,任何阅读此书的人都必须是一个心理运动员,才能在装饰器堆栈的每个级别上保留方法签名的上下文。

3)我将使用基于类的视图并重写该dispatch()方法来设置实例变量,如下所示:

class MyView(View):
    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        self.myObj = ...
        self.requester = ...
        return super(MyView, self).dispatch(*args, **kwargs)

dispatch方法就是调用您的get()/post()方法的方法。从Django文档中:

as_view入口点创建您的类的实例并调用其dispatch()方法。dispatch会查看该请求以确定其是否为GET,POST等,并将请求转发给匹配的方法(如果已定义)

然后,您可以在您的get()和/或post()视图方法中访问这些实例变量这种方法的优点是您可以将其提取到基类中,并在任意数量的View子类中使用它。由于这是标准继承,因此它在IDE中的可追溯性也更高。

有关get()请求外观的示例

class MyView(View):
    def get(self, request, id):
        print 'requester is {}'.format(self.requester)

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章