来自邻接表的嵌套 JSON
Nested JSON from adjacency list
我有一个 Flask RESTful API 应用程序,它具有以下 SQLAlchemy class 和一个代表邻接列表的自引用键:
class Medications(db.Model):
__tablename__ = 'medications'
id = Column(Integer, primary_key=True)
type = Column(String(64))
name = Column(String(64))
parent_id = Column(Integer, ForeignKey('medications.id'))
children = relationship("Medications")
我想要从 Medications class 返回的嵌套 JSON,按照
"objects": [
{
"children": [
{
"id": 4,
"name": "Child1",
"parent_id": 3,
"type": "Leaf"
},
{
"id": 5,
"name": "Child2",
"parent_id": 3,
"type": "Leaf"
}
],
"id": 3,
"name": "CardioTest",
"parent_id": null,
"type": "Parent"
}
],
根据 how-to-create-a-json-object-from-tree-data-structure-in-database 我创建了序列化程序 class
class JsonSerializer(object):
"""A mixin that can be used to mark a SQLAlchemy model class which
implements a :func:`to_json` method. The :func:`to_json` method is used
in conjuction with the custom :class:`JSONEncoder` class. By default this
mixin will assume all properties of the SQLAlchemy model are to be visible
in the JSON output. Extend this class to customize which properties are
public, hidden or modified before being being passed to the JSON serializer.
"""
__json_public__ = None
__json_hidden__ = None
__json_modifiers__ = None
def get_field_names(self):
for p in self.__mapper__.iterate_properties:
yield p.key
def to_json(self):
field_names = self.get_field_names()
public = self.__json_public__ or field_names
hidden = self.__json_hidden__ or []
modifiers = self.__json_modifiers__ or dict()
rv = dict()
for key in public:
rv[key] = getattr(self, key)
for key, modifier in modifiers.items():
value = getattr(self, key)
rv[key] = modifier(value, self)
for key in hidden:
rv.pop(key, None)
return rv
并根据 class Medications(db.Model, JsonSerializer):
将其子class 编辑到我的药物 class
然后我调用 Models.to_json()
来获得我的序列化 JSON 输出,但是,唉,对象是空的:{'parent_id': None, 'type': None, 'children': [], 'name': None, 'id': None}
但是,作为测试,如果我创建一个 Flask Restless 端点,按照
manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db)
manager.create_api(Medications, methods=['GET'])
我得到以下输出:
"objects": [
{
"children": [
{
"id": 4,
"name": "Child1",
"parent_id": 3,
"type": "Leaf"
},
{
"id": 5,
"name": "Child2",
"parent_id": 3,
"type": "Leaf"
}
],
"id": 3,
"name": "CardioTest",
"parent_id": null,
"type": "Parent"
},
{
"children": [],
"id": 4,
"name": "Child1",
"parent_id": 3,
"type": "Leaf"
},
{
"children": [],
"id": 5,
"name": "Child2",
"parent_id": 3,
"type": "Leaf"
}
],
以及一些分页信息。
很好奇为什么我从使用 JsonSerializer class 的方法中得到一个空字典。我会使用 Flask Restless 方法,但由于我将 Flask 用作 wsgi 应用程序,它会搞砸我的端点,另外,输出中不需要带有 children: []
的节点。
我的问题的解决方案最终是使用带有嵌套模式的 Marshmallow(在这个 post creating-a-tree-from-self-referential-tables-in-sqlalchemy,ala
的一点帮助下
# create SQLAlchemy object
record = db.session.query(Medications). \
options(joinedload_all("children", "children",
"children", "children",
"children", "children")).first()
class TestSchema(Schema):
name = fields.Str()
type = fields.Str()
id = fields.Int(dump_only=True)
parent_id = fields.Int(dump_only=True)
children = fields.Nested('self', many=True)
schema = TestSchema()
result = schema.dump(record)
工作得很好,不需要实现递归方法来构建树。
我有一个 Flask RESTful API 应用程序,它具有以下 SQLAlchemy class 和一个代表邻接列表的自引用键:
class Medications(db.Model):
__tablename__ = 'medications'
id = Column(Integer, primary_key=True)
type = Column(String(64))
name = Column(String(64))
parent_id = Column(Integer, ForeignKey('medications.id'))
children = relationship("Medications")
我想要从 Medications class 返回的嵌套 JSON,按照
"objects": [
{
"children": [
{
"id": 4,
"name": "Child1",
"parent_id": 3,
"type": "Leaf"
},
{
"id": 5,
"name": "Child2",
"parent_id": 3,
"type": "Leaf"
}
],
"id": 3,
"name": "CardioTest",
"parent_id": null,
"type": "Parent"
}
],
根据 how-to-create-a-json-object-from-tree-data-structure-in-database 我创建了序列化程序 class
class JsonSerializer(object):
"""A mixin that can be used to mark a SQLAlchemy model class which
implements a :func:`to_json` method. The :func:`to_json` method is used
in conjuction with the custom :class:`JSONEncoder` class. By default this
mixin will assume all properties of the SQLAlchemy model are to be visible
in the JSON output. Extend this class to customize which properties are
public, hidden or modified before being being passed to the JSON serializer.
"""
__json_public__ = None
__json_hidden__ = None
__json_modifiers__ = None
def get_field_names(self):
for p in self.__mapper__.iterate_properties:
yield p.key
def to_json(self):
field_names = self.get_field_names()
public = self.__json_public__ or field_names
hidden = self.__json_hidden__ or []
modifiers = self.__json_modifiers__ or dict()
rv = dict()
for key in public:
rv[key] = getattr(self, key)
for key, modifier in modifiers.items():
value = getattr(self, key)
rv[key] = modifier(value, self)
for key in hidden:
rv.pop(key, None)
return rv
并根据 class Medications(db.Model, JsonSerializer):
然后我调用 Models.to_json()
来获得我的序列化 JSON 输出,但是,唉,对象是空的:{'parent_id': None, 'type': None, 'children': [], 'name': None, 'id': None}
但是,作为测试,如果我创建一个 Flask Restless 端点,按照
manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db)
manager.create_api(Medications, methods=['GET'])
我得到以下输出:
"objects": [
{
"children": [
{
"id": 4,
"name": "Child1",
"parent_id": 3,
"type": "Leaf"
},
{
"id": 5,
"name": "Child2",
"parent_id": 3,
"type": "Leaf"
}
],
"id": 3,
"name": "CardioTest",
"parent_id": null,
"type": "Parent"
},
{
"children": [],
"id": 4,
"name": "Child1",
"parent_id": 3,
"type": "Leaf"
},
{
"children": [],
"id": 5,
"name": "Child2",
"parent_id": 3,
"type": "Leaf"
}
],
以及一些分页信息。
很好奇为什么我从使用 JsonSerializer class 的方法中得到一个空字典。我会使用 Flask Restless 方法,但由于我将 Flask 用作 wsgi 应用程序,它会搞砸我的端点,另外,输出中不需要带有 children: []
的节点。
我的问题的解决方案最终是使用带有嵌套模式的 Marshmallow(在这个 post creating-a-tree-from-self-referential-tables-in-sqlalchemy,ala
的一点帮助下# create SQLAlchemy object
record = db.session.query(Medications). \
options(joinedload_all("children", "children",
"children", "children",
"children", "children")).first()
class TestSchema(Schema):
name = fields.Str()
type = fields.Str()
id = fields.Int(dump_only=True)
parent_id = fields.Int(dump_only=True)
children = fields.Nested('self', many=True)
schema = TestSchema()
result = schema.dump(record)
工作得很好,不需要实现递归方法来构建树。