SQLAlchemy:添加自引用层次对象-引起sqlalchemy.orm.exc.UnmappedInstanceError

时间:2019-11-28 23:32:16

标签: json python-3.x orm sqlalchemy

来自C#/ EF世界的Python和SQLAlchemy的新手;尝试在后者中做一些非常简单的事情,所以我认为至少在前者中必须做到这一点。

问题:从JSON数据加载表,但是表由具有自引用层次结构的对象定义,例如:

class TableMixin(object):
    def __init__(self, jsonData = None):
        if(jsonData is not None):
            self.__dict__ = json.loads(jsonData)

    @declared_attr
    def __tablename__(self):
        return self.__name__

    id = Column(Integer, primary_key = True)

class HierarchyMixin(object):
    @declared_attr
    def predecessor_id(self):
        return Column(Integer, ForeignKey(self.__name__ + '.id'))

    @declared_attr
    def successors(self):
        return relationship(self.__name__)

class Something(TableMixin, HierarchyMixin, Base):
    a_property = Column(String)
    b_property = Column(String)

然后我有一些JSON数据,例如:

{
  "a_property":"some value",
  "b_property":"some other value",
  "successors":[
    {
      "a_property":"some value 1",
      "b_property":"some other value 1"
    },
    {
      "a_property":"some value 2",
      "b_property":"some other value 2"
      "successors":[
      {
        "a_property":"some value 3",
        "b_property":"some other value 3"
      }
    }
  ]
}

我的目标是将其加载到数据库中。为此,我有:

import json
from MyEntities import Something
from sqlalchemy import Table, MetaData, Column, Integer, String, ForeignKey, create_engine
from sqlalchemy.orm import mapper, sessionmaker

db_engine = create_engine('sqlite:///my.db', echo=True)
db_conn = db_engine.connect()
Session = sessionmaker(bind = db_engine)
db_sesn = Session()

with open('MyJsonData.json', encoding='utf-8-sig') as json_data_file:
    data = Something(json_data_file.read())

db_sesn.add(data)
db_sesn.commit()

它不起作用。我得到:

sqlalchemy.orm.exc.UnmappedInstanceError: Class 'Entities.Something' is mapped, but this instance lacks instrumentation.  This occurs when the instance is created before sqlalchemy.orm.mapper(Entities.Something) was called.

我四处寻找,发现一切似乎都还可以,因为所有数据都将被加载,创建以及对象层次结构。创建后,我可以通过访问该“数据”对象的各个成员进行确认。当我尝试将其添加到数据库时出现错误。

据我所知,这不应该超出我对SQLAlchemy的处理范围。但是对于我的一生,我找不到适合我的案例的具体例子。

我会要求您原谅一些可能是“非pythonic”的工作模式的时间-我还在学习:-)

1 个答案:

答案 0 :(得分:0)

我认为这只是我对Python和SqlAlchemy的新颖性,阻止了我立即看到解决方案,这实际上很简单。

在我最初的代码示例中,我做到了:

class HierarchyMixin(object):    
    def __init__(self, data = None):
        if data is not None:
            if 'successors' in data:
                self.successors = list(map(self.__class__, data['successors']))
            if 'a_property' in data:
                self.a_property = data['a_property']
            if 'b_property' in data:
                self.b_property = data['b_property']

    @declared_attr
    def predecessor_id(self):
        return Column(Integer, ForeignKey(self.__name__ + '.id'))

    @declared_attr
    def successors(self):
        return relationship(self.__name__)

    a_property = Column(String)
    b_property = Column(String)

class Something(TableMixin, HierarchyMixin, Base):
    pass

我在那里所做的全部工作就是为successors属性分配一个列表,该列表将每个成员映射到该类的新实例。而且...嗯,差不多了。

然后,使用Json数据文件,我只是:

with open('MyJsonData.json', encoding = 'utf-8-sig') as json_data:
    not_nothing = Something(json.loads(json_data.read()))

仅此而已。分层数据结构作为关系导入,并正确设置了所有predecessor_id键。

我只是因为没有立即看到这么明显的简单事情而对自己感到恼火,但是我想将其归结为学习一种新语言而不是完全 getting Python。快速变化:-)