我正在努力写下我的第一个decorator
,但我有点失落。我希望decorator
在执行main函数之前检查request
来自特定地址。
目前我有:
def check_referrer(url):
def func_wrapper():
if request.referrer == url:
return render_template('index.html', error=None)
else:
return render_template('login.html', error="some_error")
return func_wrapper
@app.route('/index', methods = ['GET'])
@check_referrer("/venue/login")
def index():
return
@ app.route / venue / login (此代码已简化)
@app.route('/venue/login', methods=['GET', 'POST'])
def login():
error = None
if login_valid():
return redirect(url_for('index'))
else:
error = 'Invalid Credentials. Please try again.'
return render_template('login.html', error=error)
1)我确信我正在做的事情有一些问题,但我首先需要理解为什么我会收到错误:
TypeError: func_wrapper() takes no arguments (1 given)
我以为我只是将argument
传递给check_referrer
。
2)我的return
陈述是否正确?
非常感谢任何帮助!
答案 0 :(得分:1)
如果用户未登录,请考虑使用Flask-Login来处理身份验证和重定向。(或者仔细检查它是如何工作的。)它比你编写的函数更有效地处理它。
您编写的功能不是装饰器,还有许多其他问题。首先,它需要结构合理。它需要3层:
request.referrer
包含整个网址,而不仅仅是与路由匹配的路径。使用urlparse
获取路径。无法保证客户端的浏览器会发送引荐来源或正确的引荐来源,因此您不应该依赖此值。
修饰函数需要接受可以传递给视图的任意参数。装饰函数应使用wraps
正确包装原始函数。
从同一视图中渲染不同的模板不是一个好主意。您应该重定向到相关视图,而不是呈现index.html
或login.html
。如果您需要将消息与重定向一起传递,请将它们放在session
。
from functools import wraps
from urllib.parse import urlparse
# or from urlparse import urlparse for py2
from flask import request, session, redirect
def check_referrer(path):
def decorator(f):
@wraps(f)
def decorated(*args, **kwargs):
if not request.referrer:
session['error'] = 'no referrer'
return redirect('login')
referrer_path = urlparse(request.referrer).path
if referrer_path != path:
session['error'] = 'expected referrer {!r}'.format(path)
return redirect('login')
return f(*args, **kwargs)
return decorated
return decorator
答案 1 :(得分:0)
理解python装饰器的关键是:
@decorator
def func():
pass
等同于:
func = decorator(func)
现在您可以理解为什么您的代码不起作用了:@check_referrer("/venue/login")
返回一个不带参数的函数func_wrapper
,因此func_wrapper
不能成为装饰器。
您可以定义一个不带有2级内部函数参数的装饰器。要制作一个带参数的装饰器,你需要另一层内部函数,正如davidism的代码所示。
以下是发生的事情:
decorator = check_referrer(url)
decorated = decorator(index)
index = decorated