【问题标题】:Returning arbitrary objects from Flask views从 Flask 视图返回任意对象
【发布时间】:2014-07-26 06:14:46
【问题描述】:

根据Flask.make_response 方法的 Flask 文档,允许从视图返回的唯一类型是 app.response_class、str、unicode、wsgi 函数或具有响应对象的元组的实例。以上。

我希望能够从视图返回我自己的模型和查询,并使用通用代码构建适当的响应、将对象序列化为可接受的格式、从查询构建集合、应用过滤条件等。连接它的最佳位置?

我考虑了以下可能性,但无法找到一种正确的方法。

  • 子类化响应和设置 app.response_class
  • 子类化 Flask 重新定义 Flask.make_response
  • 将 app.route 包装到另一个装饰器中
  • Flask.after_request
  • ?

edit1:我已经有许多 API 具有我需要在视图中实现的行为,但我想避免到处重复。

edit2:我实际上正在构建一个 Flask 扩展,其中包含我的应用程序中使用的许多默认做法。虽然普通的装饰器肯定会起作用,但我真的需要更多的魔法。

【问题讨论】:

  • 如果您正在研究烧瓶扩展,为什么不研究 flask-restless.readthedocs.org/en/latest 并看看它们如何处理序列化?
  • 我已经做到了。 Flask-restless 自动创建视图并将装饰器应用于所有视图。我不会自动化视图,所以这对我不起作用。还是谢谢。

标签: python flask


【解决方案1】:

Python 本质上是动态的,因此虽然这可能不是最佳做法,但您可以将应用程序上的 make_response 方法重新分配给任何您想要的方法。

为避免重新创建默认功能,您可以保存对原始功能的引用并使用它来实现新功能。

我最近在一个项目中使用它来添加直接从烧瓶视图返回自定义Serializable 类实例的功能。

app = Flask("StarCorp")

__original_make_response = app.make_response


def convert_custom_object(obj):

    # Check if the returned object is "Serializable"
    if not isinstance(obj, Serializable):
        # Nope, do whatever flask normally does
        return __original_make_response(obj)

    # It is, get a `dict` from `obj` using the `json` method
    data = obj.json
    data.pop(TYPE_META)  # Don't share the type meta info of an object with users

    # Let flask turn the `dict` into a `json` response
    return __original_make_response(data)  

app.make_response = convert_custom_object

由于烧瓶扩展通常提供init_app(app) 方法,我相信您可以构建一个扩展,以类似的方式猴子修补传入的应用程序对象。

【讨论】:

    【解决方案2】:

    你走得越远(make_responsedispatch_request + handle_user_errorfull_dispatch_requestrewrite Flask from scratch),你需要重新创建的功能就越多。

    在这种情况下,最简单的做法是覆盖 response_class 并在那里进行序列化 - 这让您拥有 Flask 在 make_responsefull_dispatch_request 等中所做的所有魔法,但仍然让您控制如何响应异常和序列化响应。它还保留了 Flask 的所有钩子,因此您的扩展的使用者可以覆盖他们需要的行为(并且他们可以重用他们现有的 Flask 请求/生命周期知识)

    【讨论】:

      【解决方案3】:

      你为什么不直接创建一个函数make_response_from_custom_object 并用

      结束你的视图
      return make_response_from_custom_object(custom_object)
      

      如果它很常见,我会将它放入 @response_from_custom_object 装饰器中,但挂接到 Flask 似乎有点过头了。您可以链接装饰器,因此包装 app.route 也没有意义;你只需要

      @app.route(..)
      @response_from_custom_object
      def view(...):
          ...
      

      如果你能以简单而明确的方式做到这一点,那么让你的代码变魔术并因此变得不那么容易理解是没有意义的。

      【讨论】:

      • 这当然是一个有效的解决方案,但我实际上需要做那个魔术。我正在编写一个遵循我的团队采用的模式和实践的 Flask 扩展,以便正确记录行为。我们更喜欢在后台发生一些神奇的事情,但事情会按照我们想要的方式轻松完成,而不是手动完成所有事情。
      猜你喜欢
      • 2013-11-03
      • 2015-04-18
      • 2021-12-26
      • 1970-01-01
      相关资源
      最近更新 更多