来自邻接列表的嵌套JSON

时间:2015-12-15 21:25:01

标签: python json flask sqlalchemy 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")

我想要从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"
    }
  ], 

根据how-to-create-a-json-object-from-tree-data-structure-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

并根据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类从方法中获取一个空字典。我会使用Flask Restless方法,但由于我使用Flask作为wsgi应用程序,它会搞砸我的端点,而且输出中不需要children: []的节点。

1 个答案:

答案 0 :(得分:3)

我的问题的解决方案最终使用带有嵌套架构的Marshmallow(在此帖creating-a-tree-from-self-referential-tables-in-sqlalchemy的帮助下,ala

cmd_simulator("date")

- The current date is: Thu 01/28/2016
- Enter the new date: (mm-dd-yy)

像魅力一样工作,无需实现构建树的递归方法。