【问题标题】:How to add parameters to Django class based generic view decorators?如何向基于 Django 类的通用视图装饰器添加参数?
【发布时间】:2011-09-28 23:58:53
【问题描述】:

我写了一个装饰器来显示创建对象的成功消息:

from django.contrib import messages

def success_message(klass):
    def form_valid(self, form):
        response = super(klass, self).form_valid(form)
        messages.success(self.request, 'Object added successfully')
        return response

    klass.form_valid = form_valid
    return klass

并用它来装饰基于类的通用视图:

@success_message
class BandCreateView(CreateView):
    model = Band

现在我想参数化装饰器,这样就可以了:

@success_message('Band created successfully.')
class BandCreateView(CreateView):
    model = Band

我该怎么做?我尝试将message 参数添加到success_message 但编译器抱怨参数计数不匹配,所以我认为必须有另一种方法。

【问题讨论】:

标签: python django decorator django-1.3 django-class-based-views


【解决方案1】:

看起来你必须使用闭包:

def decorator(arg):
    def wrap(klass): ...
    return wrap

因为你的电话被评估为

class BandCreateView(CreateView): ...
BandCreateView = @success_message('Band created successfully.')(BandCreateView)

注意双重调用

【讨论】:

  • 是的,刚刚想通了。。谢谢。
【解决方案2】:

我以前将这种事情作为 mixin 来做,但装饰器更有意义(并且添加到类中的麻烦更少)。您可能希望获取表单实例的详细名称,如下所示,以消除向装饰器传递消息的需要:

from django.utils.translation import ugettext_lazy as _

def ucfirst(value):
    return value[0].upper() + value[1:]

def success_message(klass):
    __orig_form_valid = klass.form_valid
    def form_valid(self, form):
        response = __orig_form_valid(self, form)
        messages.success(self.request, _("%(object)s \"%(object_name)s\" was saved successfully.") %
                         {'object': ucfirst(form.instance._meta.verbose_name), 'object_name': unicode(form.instance)})
        return response

    klass.form_valid = form_valid
    return klass

这将产生一条成功消息,类似于:

客户“ACME Inc.”已成功保存。

【讨论】:

    【解决方案3】:

    TL;DR

    无参数装饰器被声明为 class -> class 函数。
    带参数的装饰器被声明为高阶 args -> (class -> class) 函数。

    它接受参数并返回一个将接受类并返回类的函数(即“简单”装饰器)。

    说明

    t.dubrownikrelated thread 的回答确实救了我。

    无论如何,带参数的装饰器的语法有点不同——带参数的装饰器应该返回一个函数,该函数将接受一个函数并返回另一个函数。所以它应该真的返回一个普通的装饰器。

    虽然他说的是函数装饰器,但这个概念也适用于类装饰器。
    这是我得到的:

    from django.contrib import messages
    
    def success_message(message):
        def actual_decorator(klass):
            def form_valid(self, form):
                response = super(klass, self).form_valid(form)
                messages.success(self.request, message)
                return response
    
            klass.form_valid = form_valid
            return klass
    
        return actual_decorator
    

    注意actual_decorator 本身如何重复success_message 的无参数版本,以及success_message 现在如何成为更高阶函数,因为它的返回值是函数本身。

    【讨论】:

      猜你喜欢
      • 2014-05-19
      • 2017-03-08
      • 1970-01-01
      • 2015-03-07
      • 2011-08-29
      • 1970-01-01
      • 2023-02-07
      • 1970-01-01
      • 2020-07-07
      相关资源
      最近更新 更多