SQLAlchemy:添加自引用分层对象——导致 sqlalchemy.orm.exc.UnmappedInstanceError [英] SQLAlchemy: Add Self-referential Hierarchical Object -- Causing sqlalchemy.orm.exc.UnmappedInstanceError

查看:127
本文介绍了SQLAlchemy:添加自引用分层对象——导致 sqlalchemy.orm.exc.UnmappedInstanceError的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对 Python 相当陌生 &来自 C#/EF 世界的 SQLAlchemy;尝试在后者中做一些非常简单的事情,所以我认为至少在前者中它必须是可能的.

Fairly new to Python & SQLAlchemy from C#/EF world; attempting to do something which is pretty simple in the latter, so I assume it must at least be possible in the former.

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

Problem: loading table from JSON data, but table is defined by an object which has a self-referential hierarchy, like so:

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 数据,例如:

And then I have some JSON data, like:

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

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

And my goal is to load that to my database. For that I have:

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.

我四处探索,发现一切似乎都很好,因为所有数据都将加载并创建对象层次结构.一旦创建,我可以通过访问该数据"对象的各种成员来确认.在我尝试添加到数据库时出现错误.

I've poked around and found that everything seems to be okay, in the sense that all the data will load and create and object hierarchy. I can confirm by accessing various members of that "data" object, once created. The error arises at the time I attempt the add to the database.

据我所知,这不应该是我使用 SQLAlchemy 所能做的范围之外的事情.但就我的生活而言,我找不到一个具体的例子来涵盖我的情况.

From everything I can tell, this ought not be something simply outside the scope of what I can do with SQLAlchemy. But for the life of me I cannot find a specific example to cover the case I have.

我会请求暂时原谅一些可能是非pythonic"的做事模式——我还在学习:-)

I'll ask to be excused for the time-being for what might be a few "unpythonic" modes of doing things -- I'm still learning :-)

推荐答案

我认为只是我对 Python 和 SqlAlchemy 的陌生让我无法立即看到解决方案,这实际上非常简单.

I think it's only my newness to Python and SqlAlchemy which prevented me from seeing the solution to this right away, which is actually pretty simple.

坚持我最初的代码示例,我做到了:

Sticking with my initial code example, I did:

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 属性分配一个列表,该列表将每个成员映射到类的一个新实例.而且……嗯,差不多就是这样.

All I really am doing, there, is assigning a list to the successors property, and that list maps each member to a new instance of the class. And... well, that's pretty-much it.

然后,对于 Json 数据文件,我只是:

And then, with the Json data file, I just:

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

这就是全部.分层数据结构作为关系导入,并正确设置了所有的前驱_id 键.

And that's all there is to it. The hierarchical data structure imports as relational, with all the predecessor_id keys properly set.

我对自己没有立即看到如此明显简单的事情感到有点恼火,但我想这可以归结为学习一门新语言而不是获得 Python.变化很快:-)

I'm just kinda annoyed with myself for not seeing such an obviously simple thing right off the bat, but I guess chalk it up to learning a new language and not quite getting Python. That's changing fast :-)

这篇关于SQLAlchemy:添加自引用分层对象——导致 sqlalchemy.orm.exc.UnmappedInstanceError的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆