【问题标题】:Is Flask-Marshmallow's init_app() actually necessary?Flask-Marshmallow 的 init_app() 真的有必要吗?
【发布时间】:2018-07-10 14:26:40
【问题描述】:

Flask-Marshmallow documentation 对Marshmallow.init_app() 有这样的看法

使用扩展程序初始化应用程序。

code behind it 似乎做了一些与 SQLAlchemy 会话管理相关的重要事情:

def init_app(self, app):
    app.extensions = getattr(app, 'extensions', {})

    # If using Flask-SQLAlchemy, attach db.session to ModelSchema
    if has_sqla and 'sqlalchemy' in app.extensions:
        db = app.extensions['sqlalchemy'].db
        self.ModelSchema.OPTIONS_CLASS.session = db.session
    app.extensions[EXTENSION_NAME] = self

但我一直在使用和开发我的应用程序一段时间,但没有在任何地方调用init_app,而且它看起来运行良好。我正在使用 SQLAlchemy、Flask-SQLAlchemy 和 Marshmallow-SQLAlchemy(以及 Flask-Marshmallow)。

不执行ma.init_app(app) 会导致什么问题,为什么一切似乎都正常?

目前,我有一个database 和一个schema 模块; database 看起来像这样:

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Customer(db.Model):
    ...

和schema 这样:

from flask_marshmallow import Marshmallow
from database import Customer

ma = Marshmallow()

class CustomerSchema(ma.ModelSchema):
    class Meta:
        model = Customer

在我的顶级__init__.py 中,我正在这样做:

from flask import Flask
from database import db

app = Flask(__name__)
db.init_app(app)
with app.app_context():
    db.create_all()

这是一个 MVCE(放入 mvce/__init__.py,使用 PYTHONPATH=. FLASK_APP=mvce flask run 运行,然后向 localhost:5000 发出 POST 请求,并将 name 表单字段设置为某个值,然后发出 GET 请求以查看 @ 987654338@ 已正确提交到数据库):

from flask import Flask, request
from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///database.db"

@app.route("/")
def get():
    return CustomerSchema(many=True).jsonify(Customer.query.all())
@app.route("/", methods=["POST"])
def new():
    customer, errors = CustomerSchema().load(request.form)
    if errors:
        return errors, 400
    db.session.add(customer)
    db.session.commit()
    return CustomerSchema().jsonify(customer)

db = SQLAlchemy()
class Customer(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)

ma = Marshmallow()  # Not passing `app`
class CustomerSchema(ma.ModelSchema):
    class Meta:
        model = Customer

db.init_app(app)
with app.app_context():
    db.create_all()
# Note that we don't ever call `ma.init_app(app)`!

【问题讨论】:

  • 您目前如何在 Flask 应用程序中初始化 Marshmallow?像这样ma = Marshmallow(app)?
  • @OluwafemiSule 目前我在做ma = Marshmallow()(它在一个单独的模块中,所以我无权访问app)。
  • 如果您认为需要通过子类化 ma.ModelSchema 从模型构建您的 api 模式,那么您需要使用 ma.init_app 初始化您的应用程序,并将 Flask 实例传递给它。我假设你目前只是在使用ma.Schema。
  • @OluwafemiSule 不,我正在使用 ModelSchema。我已经用一些代码更新了这个问题。
  • @Josh 回答你的两个问题,是的。

标签: python flask sqlalchemy flask-sqlalchemy marshmallow


【解决方案1】:

调用flask_marshmallow.Marshmallow.init_app() 会将Flask-SQLAlchemy 创建的作用域会话绑定到flask_marshmallow.ModelSchema,flask_marshmallow.ModelSchema 与marshmallow_sqlalchemy.ModelSchema 相同,但可以避免手动传递会话对象。

flask_marshmallow.ModelSchema 可以为您提供generate schema fields from existing SQLAlchemy model,并直接将数据反序列化为 SQLAlchemy 模型。如果你不使用这个功能,你可能根本不需要 Flask-Marshmallow,但我建议使用它,调用 Flask-Marshmallow 的 init_app 是使用 ModelSchema().load 的必要条件。

【讨论】:

    【解决方案2】:

    总结问题上的cmets(非常感谢georgexsh):

    是的,init_app 是必需的,否则当您尝试使用主键 schema.load() 时会出错。此外,必须在创建任何模式之前调用它,并且必须在对 (Flask-SQLAlchemy) 数据库对象执行相同操作后调用它。 IOW,你必须按这个顺序做事:

    db = flask_sqlalchemy.SQLAlchemy()
    ma = flask_marshmallow.Marshmallow()
    db.init_app(app)
    ma.init_app(app)
    class CustomerSchema(ma.ModelSchema):
        ...
    

    因此将app 直接传递给构造函数可能更容易:

    db = flask_sqlalchemy.SQLAlchemy(app)
    ma = flask_marshmallow.Marshmallow(app)
    

    如果您的应用程序架构使这变得棘手(例如,您在 myapp/__init__.py 中定义了 app,但在 myapp/database.py 中定义了数据库模型,在 myapp/schema.py 中定义了模式),您可以将 app 的定义移动到单独的模块中,例如myapp/app.py,然后做类似的事情

    from myapp.app import app
    db = flask_sqlalchemy.SQLAlchemy(app)
    

    任何你需要使用它的地方。

    【讨论】:

    • 你同意吗?,我已经用主键模型加载了一个没有初始化棉花糖的模型,它工作了。
    猜你喜欢
    • 2018-04-05
    • 2021-01-25
    • 1970-01-01
    • 2016-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-18
    • 2017-10-29
    相关资源
    最近更新 更多