Flask装饰器:无法从URL传递参数

9

我对 Flask 还比较陌生,正在尝试使用装饰器的强大功能 :p。我读了很多东西,在这里还找到了关于 Python 装饰器的无数主题,但并没有什么真正有用的。

@app.route('groups/<id_group>')
@group_required(id_group)
@login_required
def groups_groupIndex(id_group):
    #do some stuff
    return render_template('index_group.html')

这是我得到的错误信息:
@group_required(id_group), NameError: name 'id_group' is not defined

好的,id_group还未定义,但我不明白为什么我可以在groups_groupIndex函数中使用URL的id_group参数而不能在装饰器中使用!

我尝试移动/切换装饰器,但每次都出现相同的错误。

这是我的装饰器,但它似乎工作正常。

def group_required(group_id):
    def decorated(func):
        @wraps(func)
        def inner (*args, **kwargs):
            #Core_usergroup : table to match users and groups
            groups = Core_usergroup.query.filter_by(user_id = g.user.id).all()
            for group in groups:
                #if the current user is in the group : return func
                if int(group.group_id) == int(group_id) :
                    return func(*args, **kwargs)
            flash(gettext('You have no right on this group'))
            return render_template('access_denied.html')     
        return inner
    return decorated

也许我没有正确理解装饰器的用法... 我可以这样使用我的装饰器吗?还是需要重新编写其他内容?
1个回答

14

你将 group_id 定义为函数参数;这使它成为该函数内的局部名称。

这并不意味着其他作用域(即装饰器所在的全局命名空间)可以访问该名称。

然而,wrapper 函数可以访问该名称。当调用时,它将从 @apps.route() 包装器传递该参数:

def group_required(func):
    @wraps(func)
    def wrapper(group_id, *args, **kwargs):
        #Core_usergroup : table to match users and groups
        groups = Core_usergroup.query.filter_by(user_id = g.user.id).all()
        for group in groups:
            #if the current user is in the group : return func
            if int(group.group_id) == int(group_id) :
                return func(*args, **kwargs)
        flash(gettext('You have no right on this group'))
        return render_template('access_denied.html')     
    return wrapper
请注意,这个装饰器不会将group_id参数传递给被装饰的函数;如果你仍然需要在视图函数中访问该值,请使用return func(group_id, *args, **kwargs)

我知道这是作用域问题,非常感谢,现在它完美地运行了 :) - Thomas N.
@anjalis 这样仍然会将 group_id 作为显式参数传递。在调用时,Python 会从 **... 映射中解包参数。如果测试失败,则是因为包装器没有将 group_id 传递给视图函数。 - Martijn Pieters
@sudocoder:抱歉,虽然确实缺少func,但是这里的装饰器明确期望被装饰的函数至少接受一个位置参数group_id。你提供的其他帖子可能会删除该要求,但这并不是使此装饰器正常工作的严格要求。如果它对你不起作用,那么肯定有其他问题。 - Martijn Pieters
但是如果group_id不在URL参数中,而是通过查询参数或请求正文传递呢? - Karishma Sukhwani
@KarishmaSukhwani:request对象是特殊的,只要有活动请求,它就可以在任何函数中使用。只需将group_id参数设置为带有默认值的关键字参数,例如group_id=None,并在装饰器中测试该默认值(if group_id is None:),然后查看请求以获取该值。 - Martijn Pieters
显示剩余7条评论

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