Flask 装饰器不能很好地协同工作
Flask decorators not working together nicely
我正在尝试在测试 Flask 应用程序中使用蓝图,但我 运行遇到了一个奇怪的问题。这是我的代码的相关部分:
from functools import wraps
from flask import flash, redirect, render_template, \
request, session, url_for, Blueprint
from sqlalchemy.exc import IntegrityError
from datetime import datetime
from time import localtime, strftime
from .forms import AddAppointmentForm
from project import db
from project.models import Appointment
appointments_blueprint = Blueprint('appointments', __name__)
def login_required(test):
@wraps(test)
def wrap(*args, **kwargs):
if 'logged_in' in session:
return test(*args, **kwargs)
else:
flash('You need to login first.')
return redirect(url_for('users.login'))
return wrap
@appointments_blueprint.route('/appointments/')
@login_required
def appointments():
# Get current date
current_datetime = strftime("%Y-%m-%d %H:%M:%S", localtime())
future_appointments = db.session.query(Appointment)\
.filter(Appointment.due_date >= current_datetime)\
.order_by(Appointment.due_date.asc())
past_appointments = db.session.query(Appointment)\
.filter(Appointment.due_date < current_datetime)\
.order_by(Appointment.due_date.asc())
return render_template('appointments.html',
form = AddAppointmentForm(request.form),
future_appointments=future_appointments,
past_appointments=past_appointments)
现在,当我 运行 应用程序时,出现此错误:
File "/home/mosquito/git/flask-scheduler/project/appointments/views.py", line 72, in <module>
@login_required
File "/home/mosquito/python_envs/flask-scheduler/local/lib/python2.7/site-packages/flask/blueprints.py", line 160, in decorator
endpoint = options.pop("endpoint", f.__name__)
AttributeError: 'NoneType' object has no attribute '__name__'
查看 blueprints.py,我看到了这个:
def route(self, rule, **options):
"""Like :meth:`Flask.route` but for a blueprint. The endpoint for the
:func:`url_for` function is prefixed with the name of the blueprint.
"""
def decorator(f):
endpoint = options.pop("endpoint", f.__name__)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
这失败了,因为 'f' 是 None。现在更有趣了,如果我删除
@login_required
decorator,到了那个点,f是一个函数,就OK了。
另一方面,如果我删除
@appointments_blueprint.route()
装饰器,它也可以。所以看起来这两个装饰器的组合导致 f 成为 None...知道这里发生了什么吗?
您需要取消缩进 return
行:
def login_required(test):
@wraps(test)
def wrap(*args, **kwargs):
if 'logged_in' in session:
return test(*args, **kwargs)
else:
flash('You need to login first.')
return redirect(url_for('users.login'))
return wrap
你把它变成了 wrap
函数本身的一部分,所以外部装饰器函数没有返回任何东西。
删除 @appointments_blueprint.route()
根本不会注册路由,因此您永远不会发现您将 appointments
设置为 None
。
我正在尝试在测试 Flask 应用程序中使用蓝图,但我 运行遇到了一个奇怪的问题。这是我的代码的相关部分:
from functools import wraps
from flask import flash, redirect, render_template, \
request, session, url_for, Blueprint
from sqlalchemy.exc import IntegrityError
from datetime import datetime
from time import localtime, strftime
from .forms import AddAppointmentForm
from project import db
from project.models import Appointment
appointments_blueprint = Blueprint('appointments', __name__)
def login_required(test):
@wraps(test)
def wrap(*args, **kwargs):
if 'logged_in' in session:
return test(*args, **kwargs)
else:
flash('You need to login first.')
return redirect(url_for('users.login'))
return wrap
@appointments_blueprint.route('/appointments/')
@login_required
def appointments():
# Get current date
current_datetime = strftime("%Y-%m-%d %H:%M:%S", localtime())
future_appointments = db.session.query(Appointment)\
.filter(Appointment.due_date >= current_datetime)\
.order_by(Appointment.due_date.asc())
past_appointments = db.session.query(Appointment)\
.filter(Appointment.due_date < current_datetime)\
.order_by(Appointment.due_date.asc())
return render_template('appointments.html',
form = AddAppointmentForm(request.form),
future_appointments=future_appointments,
past_appointments=past_appointments)
现在,当我 运行 应用程序时,出现此错误:
File "/home/mosquito/git/flask-scheduler/project/appointments/views.py", line 72, in <module>
@login_required
File "/home/mosquito/python_envs/flask-scheduler/local/lib/python2.7/site-packages/flask/blueprints.py", line 160, in decorator
endpoint = options.pop("endpoint", f.__name__)
AttributeError: 'NoneType' object has no attribute '__name__'
查看 blueprints.py,我看到了这个:
def route(self, rule, **options):
"""Like :meth:`Flask.route` but for a blueprint. The endpoint for the
:func:`url_for` function is prefixed with the name of the blueprint.
"""
def decorator(f):
endpoint = options.pop("endpoint", f.__name__)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
这失败了,因为 'f' 是 None。现在更有趣了,如果我删除
@login_required
decorator,到了那个点,f是一个函数,就OK了。
另一方面,如果我删除
@appointments_blueprint.route()
装饰器,它也可以。所以看起来这两个装饰器的组合导致 f 成为 None...知道这里发生了什么吗?
您需要取消缩进 return
行:
def login_required(test):
@wraps(test)
def wrap(*args, **kwargs):
if 'logged_in' in session:
return test(*args, **kwargs)
else:
flash('You need to login first.')
return redirect(url_for('users.login'))
return wrap
你把它变成了 wrap
函数本身的一部分,所以外部装饰器函数没有返回任何东西。
删除 @appointments_blueprint.route()
根本不会注册路由,因此您永远不会发现您将 appointments
设置为 None
。