Flask-Marshmallow 的 init_app() 真的有必要吗?
Is Flask-Marshmallow's init_app() actually necessary?
Flask-Marshmallow documentation 对 Marshmallow.init_app()
有话要说
Initializes the application with the extension.
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 请求以查看 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)`!
调用 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
.[=18 所必需的=]
总结对问题的评论(非常感谢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)
任何需要使用它的地方。
Flask-Marshmallow documentation 对 Marshmallow.init_app()
Initializes the application with the extension.
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 请求以查看 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)`!
调用 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
.[=18 所必需的=]
总结对问题的评论(非常感谢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)
任何需要使用它的地方。