当在Python中对该项目使用装饰器时,为什么Flask的url_for会引发错误? [英] Why does Flask's url_for throw an error when using a decorator on that item in Python?

查看:112
本文介绍了当在Python中对该项目使用装饰器时,为什么Flask的url_for会引发错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个Python Flask应用,并在下面创建了装饰器和视图。装饰器在查看索引时效果很好,但是当您注销并使用 url_for 索引重定向时,它将引发构建错误。

I am creating a Python Flask app and created the decorator and views below. The decorator works great when viewing the index, but when you logout and it redirects using the url_for index it throws a builderror. Why would

def logged_in(fn):
    def decorator():
        if 'email' in session:
            return fn()
        else:
            return render_template('not-allowed.html', page="index")
    return decorator


@app.route('/')
@logged_in
def index():
    email = session['email']    
    return render_template('index.html', auth=True, page="index", marks=marks)

@app.route('/sign-out')
def sign_out():
    session.pop('email')
    print(url_for('index'))
    return redirect(url_for('index'))

有什么想法吗?错误为: BuildError:('index',{},无)

Any ideas? The error is: BuildError: ('index', {}, None)

推荐答案

这里的问题是您返回的 decorator()函数的名称与它要修饰的函数的名称不同,因此URL构建器找不到您的索引视图。您需要使用 functools 模块中的 wraps()装饰器来复制原始函数的名称。另一个问题(您仍然必须遇到)是您不接受装饰器中的参数并将其传递给原始函数。这是经过纠正的修饰符:

The problem here is that decorator() function which you return has different name than the function it is decorating, so the URL builder can't find your index view. You need to use wraps() decorator from functools module to copy the name of the original function. Another problem (which you still have to encounter) is that you don't accept the arguments in your decorator and pass it to the original function. Here's is the corrected decorator:

from functools import wraps

def logged_in(fn):
    @wraps(fn)
    def decorator(*args, **kwargs):
        if 'email' in session:
            return fn(*args, **kwargs)
        else:
            # IMO it's nicer to abort here and handle it in errorhandler.
            abort(401)
    return decorator






更多的解释:在Python decorator中,该函数将另一个函数作为其参数并返回一个函数作为其结果。因此,以下


A bit more explanations: in Python decorator is a function which takes another function as its argument and returns a function as its result. So the following

@logged_in
def index(): pass

本质上与

def index(): pass
index = logged_in(index)

这种情况下的问题是 logged_in 装饰器返回的不是原始函数,而是一个包装器(在您的代码中称为 decorator ),用于包装原始包装器功能。该包装器的名称(装饰器)与其包装的原始函数不同。现在 app.route()装饰器(在 logged_in 之后调用)会看到此新函数并使用其名称(装饰器)为其注册路线。问题出在这里:您希望修饰后的函数具有相同的名称( index ),因此可以在 url_for()以获得路线。这就是为什么您需要手动复制名称的原因

The problem in this case was that what your logged_in decorator returns is not the original function, but a wrapper (called decorator in your code), which wraps the original function. This wrapper has a different name (decorator) than the original function it is wrapping. Now app.route() decorator, which you call after logged_in, sees this new function and uses its name (decorator) to register a route for it. Here lies the problem: you want the decorated function to have the same name (index), so it could be used in url_for() to get a route for it. That's why you need to copy the name manually

decorator.__name__ = fn.__name__

或更好地使用 update_wrapper 包裹 functools 模块的帮助程序,它可以为您提供甚至更多的帮助。

or better use update_wrapper and wraps helpers from functools module, which do that and even more for you.

这篇关于当在Python中对该项目使用装饰器时,为什么Flask的url_for会引发错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆