简体   繁体   English

来自邻接列表的嵌套JSON

[英]Nested JSON from adjacency list

I have a Flask RESTful API app that has the following SQLAlchemy class with a self-referential key representative of an adjacency list: 我有一个Flask RESTful API应用程序,它具有以下SQLAlchemy类,其中一个自引用键代表邻接列表:

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")

I want nested JSON returned from the Medications class, along the lines of 我希望从Medications类中返回嵌套的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"
    }
  ], 

As per how-to-create-a-json-object-from-tree-data-structure-in-database I created the serializer class 根据如何创建一个json-object-from-tree-data-in-database-in-database我创建了序列化器类

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

and subclassed this to my Medications class, as per class Medications(db.Model, JsonSerializer): 并将其子类化为我的Medications类,按class Medications(db.Model, JsonSerializer):

I then call Models.to_json() to get my serialized JSON output, but alas, the object is empty: {'parent_id': None, 'type': None, 'children': [], 'name': None, 'id': None} 然后我调用Models.to_json()来获取序列化的JSON输出,但是,对象是空的: {'parent_id': None, 'type': None, 'children': [], 'name': None, 'id': None}

However, as a test, if I create a Flask Restless endpoint, as per 但是,作为测试,如果我创建一个Flask Restless端点,按照

manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db)
manager.create_api(Medications, methods=['GET'])

I get the following output: 我得到以下输出:

"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"
    }
  ], 

along with some pagination information. 以及一些分页信息。

Am curious why I am getting an empty dictionary from the method using the JsonSerializer class. 很好奇为什么我从使用JsonSerializer类的方法获取一个空字典。 I would use the Flask Restless method, but since I am using Flask as a wsgi app, it would screw up my endpoints, plus, the nodes with children: [] are not desired in the output. 我会使用Flask Restless方法,但由于我使用Flask作为wsgi应用程序,它会搞砸我的端点,而且,输出中不需要带有children: []节点的节点children: []

The solution to my issue ended up being using Marshmallow with a nested schema (with a little assistance from this post creating-a-tree-from-self-referential-tables-in-sqlalchemy , ala 我的问题的解决方案最终使用了带有嵌套模式的Marshmallow(在这个帖子中提供了一些帮助, 创建了一个来自自我引用的表 - 在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)

Worked like a charm, and no need to implement a recursive method to build the tree. 像魅力一样工作,不需要实现一个递归方法来构建树。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM