烧瓶装饰器不能很好地协同工作

Ale*_*oVK 0 python decorator flask python-decorators

我正在尝试在测试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)
Run Code Online (Sandbox Code Playgroud)

现在当我运行应用程序时,我收到此错误:

  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__'
Run Code Online (Sandbox Code Playgroud)

看看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
Run Code Online (Sandbox Code Playgroud)

这失败是因为'f'是None.现在甚至更有趣,如果我删除了

@login_required
Run Code Online (Sandbox Code Playgroud)

装饰器,当它到达那个点时,f是一个函数,所以没关系.

另一方面,如果我删除了

@appointments_blueprint.route()
Run Code Online (Sandbox Code Playgroud)

装饰,它也有效.所以看起来两个装饰器的组合导致f为None ....任何想法在这里发生了什么?

Mar*_*ers 6

你需要取消该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
Run Code Online (Sandbox Code Playgroud)

你把它作为wrap函数本身的一部分,所以外部装饰器函数什么也没有返回.

删除@appointments_blueprint.route()简单不会注册路由,所以你永远不会发现你设置appointmentsNone.