Python Bottle.py 装饰器困惑

0 投票
3 回答
2769 浏览
提问于 2025-04-17 08:55

我有一个叫做“auth”的装饰器。

def auth(check_func=validate_login):
    def decorator(view):
        def wrapper(*args, **kwargs):
            auth = check_func()
            if auth:
                return view(*args, **kwargs)
            return bottle.redirect('/login.html')
        return wrapper
    return decorator

这个 auth 装饰器是这样使用的:

@get('/')
@view("someview")
@auth()
def handler():
   #myhandlercode

所以这个 auth 装饰器会调用 view 函数,这个函数在 bottle.py 中渲染我的模板。但现在我想返回 JSON,而不是渲染一个 view。我需要对 auth 装饰器的代码做什么修改才能实现这个?我有点困惑,不知道怎么从 auth 代码中调用处理器,而不是 view

编辑 1:Bottle 允许你返回字典,它会直接把字典转换成 JSON。而我根本不想使用 view,我只想从我的处理器返回 JSON 给用户。那么我是不是应该直接去掉 @view 装饰器?在 auth 装饰器中我应该调用什么呢?

3 个回答

0

你是从你的视图中返回Json(其实就是一个Python字典),对吧?在这种情况下,你不需要对装饰器做任何修改。视图返回的内容并不会直接发送到用户的浏览器,而是先经过Bottle框架的处理,然后再返回给用户。当你从视图返回一个字典时,它会被当作Json来处理;而如果返回的是一个模板字符串,那就会被当作Html来处理。

1

我觉得把认证和JSON输出搞在一起是不太合适的。

这里有个用普通Python的装饰器的例子:

def validate():
    return True

def auth(valid=validate):
    def _auth(f):
        def _auth_wrap():
            if not valid():
                raise Exception('redirect')
            return f()
        return _auth_wrap
    return _auth

def view(tmpl):
    def _view(f):
        def _view_wrap():
            return tmpl.format(f())
        return _view_wrap
    return _view

@view('Hello, {0}')
@auth()
def handler():
    return 'World'

handler
# outputs: __main__._view_wrap
handler()
# outputs: 'Hello, World'

还有这一行:

return tmpl.format(f())

这个f函数是__main__._auth_wrap,它在调用验证函数并返回执行的处理程序。

所以,处理JSON输出的方式应该和上面提到的tmpl.format不一样,比如可以调用一个单独的方法并传递所需的信息,或者把它放进视图装饰器里,这样做会更合适。

为了更好地回答最后的问题,如果你想根据请求动态决定是否输出JSON,而的视图函数不支持这个功能,那么你可以像上面那样创建一个视图包装器,检查请求对象或者你想用来决定JSON输出的其他东西,然后在_view_wrap中调用的视图或者json.dumps来处理f()

如果你想让一个函数总是输出JSON,那就删除视图装饰器,创建一个类似于上面视图装饰器的JSON装饰器,这样它会return json.dumps(f())

这里的主要观点是让认证保持它的本职工作。

3

Bottle的路由装饰器可以在不影响自动生成JSON功能的情况下,给你添加装饰器。

@get('/', apply=[auth])
def handler():
    ...

如果你不想要某个视图,只需要去掉你的@view装饰器,Bottle会很聪明地处理字典,把它转换成JSON格式的回答。

撰写回答