根据对象值在基于类的视图Django中应用Decorator

时间:2015-03-17 14:54:34

标签: python django decorator

我有一个这样的模型:

class Test(models.Model):
    is_private = models.BooleanField(default=False)

我有这样的观点:

class TestDetaiView(View):
    def get(self, request, pk):
         return render(request, 'test.html', {'story': Story.objects.get(pk=pk)}

现在,我想要做的是:如果test是私有的,则应用vary_on_cookie装饰器,否则使用cache_page装饰器。

怎么做?

2 个答案:

答案 0 :(得分:2)

这里的关键问题是你想在运行时选择装饰器,但通常的装饰器语法是在类声明时触发的。幸运的是,装饰器只是常规的Python callables,因此如果需要,可以在运行时应用它们。

有许多不同的方法可以构建它。下面我创建了一个自定义装饰器,因为这将允许您在多个CBV中重复使用相同的代码。 (当然,这可以进一步推广。)

请注意,正如the documentation中所讨论的,在CBV中应用Django装饰器的正确位置是dispatch()方法;并且您需要使用method_decorator来使Django的内置装饰器适合与类一起使用。

def test_decorator(dispatch_wrapped):
    def dispatch_wrapper(self, request, *args, **kwargs):
        # presumably you're filtering on something in request or the url
        is_private = Test.objects.get(...).is_private

        decorator = vary_on_cookie if is_private else cache_page(60 * 15)
        dispatch_decorated = method_decorator(decorator)(dispatch_wrapped)

        return dispatch_decorated(self, request, *args, **kwargs)

    return dispatch_wrapper

class TestDetaiView(View):
    @test_decorator
    def dispatch(self, *args, **kwargs):
        # any custom dispatch code, or just...
        super().dispatch(*args, **kwargs)

如果这令人困惑,可能有助于阅读有关装饰器以及它们如何定义和使用的更多信息。

答案 1 :(得分:0)