Django类视图使用装饰器和会话。

3
我正在尝试将一些Django视图从基于函数的视图转换为基于类的视图,但遇到了一些小问题。
我的面向对象编程有点薄弱,我认为问题在于我不知道事情的去向。
我有一个需要在视图上使用的自定义登录装饰器,因此我需要...
首先,我有来自此示例的View类 http://www.djangosnippets.org/snippets/760/ 然后我的视图类看起来像这样...
class TopSecretPage(View):
    @custom_login
    def __call__(self, request, **kwargs):
        #bla bla view stuff...
        pass

问题在于我的装饰器由于某些原因无法访问request.session...

我的装饰器如下所示...

def myuser_login_required(f):
    def wrap(request, *args, **kwargs):

        # this check the session if userid key exist,
        # if not it will redirect to login page

        if 'field' not in request.session.keys():
        return wrap

我认为我错过了一些简单的东西,感谢大家的耐心!

更新: 好的,这是我得到的错误信息...

"ViewDoesNotExist: 在项目名称应用视图模块中尝试了TopSecretPage。错误是:类型对象'TopSecretPage'没有属性'session'"

我还将装饰器简化为以下形式....

def myuser_login_required(request, *args, **kwargs):


    # this check the session if userid key exist,
    # if not it will redirect to login page

    if 'username' not in request.session.keys():
        return  HttpResponseRedirect(reverse("login-page"))

    return True
5个回答

6

对于应用于任何基于类的视图方法的任何装饰器,正确的方法是使用 django.utils.decorators.method_decorator()。我不确定 method_decorator() 是什么时候引入的,但这里有一个 Django 1.2 版本的示例/更新说明 release notes。使用方式如下:

from django.utils.decorators import method_decorator

class TopSecretPage(View):
    @method_decorator(custom_login)
    def __call__(self, request, **kwargs):
        #bla bla view stuff...
        pass

你能引用一下吗?你是说基于类的视图是Django 1.2推荐的视图方式吗?出于维护原因,我已经不再使用基于类的视图了。 - Thomas Schultz
请查看1.2版本说明的此部分内容: - Gert Steyn
https://docs.djangoproject.com/en/1.3/releases/1.2/#user-passes-test-login-required-and-permission-required - Gert Steyn
@ThomasSchultz 什么维护原因?你是在建议人们避免使用基于类的视图吗?我到目前为止还没有遇到任何问题。 - Stephen Paulger
1
我认为这更多是一个纪律性的问题。我们发现基于类的视图往往会快速增长并增加许多复杂性。此外,很容易开始更多地复制代码。然后你就会开始有像“基础”视图类之类的东西。我们发现我们可以使用函数视图,这些视图更易于维护,复杂度更低,调试也更容易。只是我们的经验而已。类视图确实有效,我们使用它们将近2年了。 - Thomas Schultz

3
问题在于您的包装器希望将“请求”作为第一个参数,但类上的方法始终将“self”作为第一个参数。因此,在您的装饰器中,它认为是请求对象实际上是TopSecretPage本身。
Vinay或artran的解决方案都应该有效,因此我不会重复它们。只是想提供更清晰的问题描述可能会有所帮助。

2
这个问题以前before出现过。包含一个可能适用于您的解决方案。
更新:带装饰器的示例方法:
class ContentView(View):

    # the thing in on_method() is the actual Django decorator
    #here are two examples
    @on_method(cache_page(60*5))
    @on_method(cache_control(max_age=60*5))
    def get(self, request, slug): # this is the decorated method
        pass #in here, you access request normally

嗯,就像我之前说的,我的oop技能很弱,实际上在发布这个问题之前已经读过那篇文章了。但是我不知道如何从那个例子中访问装饰器函数中的请求对象。 - Thomas Schultz
谢谢更新!但我还是有问题哈哈。我会更新我的问题尝试展示它... - Thomas Schultz
对于Django 1.5,它是:`@method_decorator(cache_control(max_age=86400)) def get(self, request, *args, **kwargs):` - chrishiestand

1

1

你可以在 URL 上使用装饰器,而不是在视图上使用。

例如,在 urls.py 中:

from my_decorators import myuser_login_required
from my_views import TopSecretPage

urlpatterns = patterns('', 
    (r'^whatever-the-url-is/$', myuser_login_required(TopSecretPage), {}),
)

你可能需要稍微调整一下,但大致上是正确的。


我认为这个解决方案应该可以工作,但你需要实例化TopSecretPage:myuser_login_required(TopSecretPage())。 - Carl Meyer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接