如何使用请求编写 Flask 装饰器?

Posted

技术标签:

【中文标题】如何使用请求编写 Flask 装饰器?【英文标题】:How to write Flask decorator with request? 【发布时间】:2014-12-31 10:02:25 【问题描述】:

我不确定为什么以下装饰器 [validate_request] 不起作用。编写此类验证装饰器的正确方法是什么?

def validate_request(req_type):
    if req_type is 'json' and not request.json:
        abort(400)
    def decorator(func):
        @functools.wraps(func)
        def wrapped_func(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapped_func
    return decorator

@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['PUT'])
@validate_request('json')
@json
def update_task(task_id):
#    task = filter(lambda t: t['id'] == task_id, tasks)
    task = [task for task in tasks if task['id'] == task_id]
    if len(task) == 0:
        abort(404)

    #update task
    for field in ['title', 'description', 'done']:
        task[0][field] = request.json.get(field, task[0][field])

错误:-

Traceback (most recent call last):
  File "C:\AGR\Programming\LearningPython\FlaskLearning\flask_rest\app.py", line 156, in <module>
    @validate_request('json')
  File "C:\AGR\Programming\LearningPython\FlaskLearning\flask_rest\app.py", line 144, in validate_request
    if req_type is 'json' and not request.json:
  File "C:\Anaconda\lib\site-packages\werkzeug\local.py", line 338, in __getattr__
    return getattr(self._get_current_object(), name)
  File "C:\Anaconda\lib\site-packages\werkzeug\local.py", line 297, in _get_current_object
    return self.__local()
  File "C:\Anaconda\lib\site-packages\flask\globals.py", line 20, in _lookup_req_object
    raise RuntimeError('working outside of request context')
RuntimeError: working outside of request context

这应该如何以更惯用的方式完成???

【问题讨论】:

您需要将and not request.json 部分移动到装饰器函数内,否则在将装饰器应用于视图函数时(即在导入时)而不是视图时对其进行评估正在调用函数,因此还没有可用的请求对象 其实只是把整个if req_type is 'json' and not request.json: abort(400)放在装饰器里面 request.json 无论如何都已弃用,请使用 request.get_json() 【参考方案1】:

这就是你的装饰器的样子

def validate_request(f):
  @functools.wraps(f)
  def decorated_function(*args, **kwargs):
    # Do something with your request here
    data = flask.request.get_json()
    if not data:
      flask.abort(404)
    return f(*args, **kwargs)
  return decorated_function

你会这样称呼它

@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['PUT'])
@validate_request
def update_task(task_id):
    # The rest of your code..

【讨论】:

究竟是什么导致了这里的 RuntimeError?【参考方案2】:

这是一个旧帖子,但我认为它可能会受益于一些更正: decorated_function需要返回f(*args, **kws)

def validate_request(f):
  @functools.wraps(f)
  def decorated_function(*args, **kws):
    # Do something with your request here
    data = flask.request.get_json()
    if not data:
      flask.abort(404)
    return f(*args, **kws)
  return decorated_function

否则会遇到TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.

【讨论】:

很好的捕捉,我是凭记忆写的,显然它溜走了,我希望你不介意在我现有的答案中添加缺失的回报!干杯! 当然!我很高兴我的回答有助于改善您的回答

以上是关于如何使用请求编写 Flask 装饰器?的主要内容,如果未能解决你的问题,请参考以下文章

你如何使用 Flask-Login 和自定义 Python 装饰器来分配用户权限?

如何在 Flask 中实现登录所需的装饰器

flask login_required 装饰器位置 - 从头开始​​编写

在Flask装饰器功能中获取IP地址和端口[重复]

如何将装饰器应用于每个 Flask 视图

python 装饰器在Flask中验证发布请求