1

Flask-Marshmallow 文档有这样的说法Marshmallow.init_app()

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

它背后的代码似乎做了一些与 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 请求以查看Customer是否正确提交到数据库):

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)`!
4

2 回答 2

2

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

flask_marshmallow.ModelSchema可以为您从现有的 SQLAlchemy 模型生成模式字段,并将数据直接反序列化为 SQLAlchemy 模型。如果您不使用此功能,您可能根本不需要 Flask-Marshmallow,但我建议使用它,调用 Flask-Marshmallowinit_app是使用ModelSchema().load.

于 2018-02-01T08:59:49.867 回答
1

总结对该问题的评论(非常感谢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)

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

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

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

于 2018-02-02T12:00:40.623 回答