[英]Use DB data model to generate SQLAlchemy models, schemas, and JSON response
將 Flask 和 SQLAlchemy 用於 Python 網絡應用程序,我的目標是創建一個系統,我可以在其中:
所有這些都將打包在一個層中,在編寫 API 時應該允許簡單的數據訪問、驗證和響應格式化,希望無需手動定義數據模型或模式,而不是超越數據庫中已經存在的定義。 這引出了我的問題:
我可以利用現有的框架來完成我想要完成的所有事情嗎? 我不希望有一個庫可以做所有事情,但我希望能夠利用幾個現有的框架。 但是,我遇到了直接沖突,尤其是在第 2 步和第 3 步中。到目前為止,我一直在嘗試使用的堆棧如下:
我有第 1 步的解決方案:SQLAlchemy 的反射。 這允許我讀取現有數據庫中的表並將它們映射到 SQLAlchemy 模型。 這很好用。
第 2 步和第 3 步的組合變得模糊 - 我正在嘗試使用 Flask-Marshmallow 和 Marshmallow-JsonAPI。 Flask-Marshmallow 具有ModelSchema 類,它允許您通過將現有的 SQLAlchemy 模型傳遞給它來生成模式。 我可以將我在第 1 步中生成的 SQLAlchemy 模型傳遞給它,滿足我在第 2 步中的標准。至於 Marshmallow-JsonAPI,它具有可以為模型定義架構的功能,並且它會自動創建符合 JSONAPI 的響應,滿足我的第 3 步標准。我可以單獨使用這些框架中的每一個來執行我需要的操作。
不幸的是,由於我的架構必須從 Flask-Marshmallow 和 Marshmallow-JSONAPI 中的 Schema 類繼承,我遇到了問題。 我的“虛擬”類模型如下所示:
import flask
from marshmallow_jsonapi import Schema, fields
from sqlalchemy.ext.declarative import DeferredReflection
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
app = flask.Flask(__name__)
DB = SQLAlchemy()
DB.init_app(app)
MA = Marshmallow(app)
DeferredReflection.prepare(DB.get_engine(app))
class Dummy(DeferredReflection, DB.Model):
__tablename__ = "dummy" # This model will be reflected from the Dummy table
class DummySchema(MA.ModelSchema, Schema): # The problem line
class Meta:
model = Dummy # Create schema for the Dummy model
在嘗試啟動我的 API 時,我收到如下奇怪的錯誤:
api_1 | [2017-01-05 23:16:13,379] ERROR in app: Exception on /api/dummy [POST]
api_1 | Traceback (most recent call last):
api_1 | File "/usr/local/lib/python3.5/site-packages/flask/app.py", line 1612, in full_dispatch_request
api_1 | rv = self.dispatch_request()
api_1 | File "/usr/local/lib/python3.5/site-packages/flask/app.py", line 1598, in dispatch_request
api_1 | return self.view_functions[rule.endpoint](**req.view_args)
api_1 | File "/usr/local/lib/python3.5/site-packages/flask_restful/__init__.py", line 477, in wrapper
api_1 | resp = resource(*args, **kwargs)
api_1 | File "/usr/local/lib/python3.5/site-packages/flask/views.py", line 84, in view
api_1 | return self.dispatch_request(*args, **kwargs)
api_1 | File "/usr/local/lib/python3.5/site-packages/flask_restful/__init__.py", line 587, in dispatch_request
api_1 | resp = meth(*args, **kwargs)
api_1 | File "/dummyproj/api/src/dummyproj/api/v1/dummy_resource.py", line 34, in post
api_1 | dummy_schema = dummy.DummySchema()
api_1 | File "/usr/local/lib/python3.5/site-packages/marshmallow_sqlalchemy/schema.py", line 143, in __init__
api_1 | super(ModelSchema, self).__init__(*args, **kwargs)
api_1 | File "/usr/local/lib/python3.5/site-packages/marshmallow_jsonapi/schema.py", line 81, in __init__
api_1 | super(Schema, self).__init__(*args, **kwargs)
api_1 | File "/usr/local/lib/python3.5/site-packages/marshmallow/schema.py", line 358, in __init__
api_1 | self._update_fields(many=many)
api_1 | File "/usr/local/lib/python3.5/site-packages/marshmallow/schema.py", line 750, in _update_fields
api_1 | self.__set_field_attrs(ret)
api_1 | File "/usr/local/lib/python3.5/site-packages/marshmallow/schema.py", line 772, in __set_field_attrs
api_1 | self.on_bind_field(field_name, field_obj)
api_1 | File "/usr/local/lib/python3.5/site-packages/marshmallow_jsonapi/schema.py", line 164, in on_bind_field
api_1 | field_obj.load_from = self.inflect(field_name)
api_1 | File "/usr/local/lib/python3.5/site-packages/marshmallow_jsonapi/schema.py", line 190, in inflect
api_1 | return self.opts.inflect(text) if self.opts.inflect else text
api_1 | AttributeError: 'SchemaOpts' object has no attribute 'inflect'
似乎由於我的 Schema 類繼承自兩個不同的超類,因此會導致問題。 我希望這兩個棉花糖庫非常兼容,但似乎確實存在問題。
所有這一切的結果是,我不太確定接下來要嘗試什么。 我並不是真的期待任何關於 Marshmallow 框架的具體建議,更多只是想展示我的思路。 是否有圍繞這種設計的最佳實踐,或者我是否試圖一次解決太多問題?
(Python 和 SO 的新手 - 如果其中任何一個不清楚,請道歉)。
我成功地結合了 marshmallow-jsonapi + marshmallow-sqlalchemy。 這是魔法:
import marshmallow
import marshmallow_jsonapi
import marshmallow_jsonapi.flask
import marshmallow_sqlalchemy
import myapp.database as db
def make_jsonapi_schema_class(model_class):
class SchemaOpts(marshmallow_sqlalchemy.SQLAlchemyAutoSchemaOpts, marshmallow_jsonapi.SchemaOpts):
pass
class Schema(marshmallow_sqlalchemy.SQLAlchemyAutoSchema, marshmallow_jsonapi.flask.Schema):
OPTIONS_CLASS = SchemaOpts
@marshmallow.post_load
def make_instance(self, data, **kwargs):
# Return deserialized data as a dict, not a model instance
return data
# You can add default behavior here, for example
# id = fields.Str(dump_only=True)
# https://marshmallow-sqlalchemy.readthedocs.io/en/latest/recipes.html#automatically-generating-schemas-for-sqlalchemy-models
class Meta:
# Marshmallow-SQLAlchemy
model = model_class
sqla_session = db.session
# Marshmallow-JSONAPI
type_ = model_class.__name__.lower()
self_view = type_ + '_detail'
self_view_kwargs = {'id': '<id>'}
self_view_many = type_ + '_list'
schema_class = type(model_class.__name__ + 'Schema', (Schema,), {'Meta': Meta})
return schema_class
然后你打電話
FooSchema = make_jsonapi_schema_class(Foo)
從您的 SQLAlchemy 聲明模型生成棉花糖模式類。 如果您想自定義它,您可以反過來繼承該類。
(為了實現 REST API,我使用了Flask-REST-JSONAPI ,它建立在 Flask + SQLAlchemy + marshmallow-jsonapi 之上。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.