0

我收到了一个我不理解 AbstractConcreteBase 的错误

在 my_enum.py

class MyEnum(AbstractConcreteBase, Base):
    pass

在 enum1.py

class Enum1(MyEnum):
    years = Column(SmallInteger, default=0)

# class MyEnums1:
#    NONE = Enum1()
#    Y1 = Enum1(years=1)

在 enum2.py

class Enum2(MyEnum):
    class_name_python = Column(String(50))

在 test.py 中

from galileo.copernicus.basic_enum.enum1 import Enum1
from galileo.copernicus.basic_enum.enum2 import Enum2
#...

如果我取消注释 enum1.py 中的三行,我会在第二次导入时收到以下错误。

AttributeError:类型对象“MyEnum”没有属性“

但是没有 MyEnums1 它可以正常工作,或者在单独的文件中使用 MyEnums1 它可以正常工作。为什么这种实例化会影响导入?无论如何我可以将 MyEnums1 保存在同一个文件中吗?

4

1 回答 1

2

abstractconcretebase 的目的是将非标准的操作顺序应用于标准映射过程。通常,映射的工作方式如下:

  1. 定义要映射的类
  2. 定义一个表
  3. 使用 mapper() 将类映射到表。

声明式本质上结合了这三个步骤,但这就是它的作用。

当使用抽象的具体基时,我们需要执行这个完全特殊的步骤——基类需要映射到子类映射到的所有表的联合。因此,如果您有 enum1 和 enum2,则“Base”需要映射到本质上“select * from enum1 UNION ALL select * from enum2”。

这种到 UNION 的映射不能零碎发生;MyEnum 基类必须同时将每个子表的完整 UNION 呈现给 mapper()。因此 AbstractConcreteBase 执行重新安排声明性工作方式的复杂任务,以便在映射器配置发生之前根本不映射基 MyEnum ,这在您第一次实例化映射类时发生。然后它将自己插入为所有现有映射子类的映射基础。

所以基本上通过像这样在类级别实例化一个 Enum1() 对象,您太早地调用了 configure_mappers() ,这样当 Enum2() 出现时,abstractconcretebase 已经烘焙并且过程失败。

除此之外,在类级别实例化像 Enum1() 这样的映射类是完全不正确的。ORM 映射对象与全局对象完全相反,必须始终在特定会话的本地创建。

编辑:这些类也应该有 {"concrete": True} ,这是您收到此消息的部分原因。我想看看这个消息是否可以改进。

编辑2:是的,这里的机制很奇怪。我已经提交了一些跳过此特定错误消息的其他内容,尽管它现在会以不同的方式失败并且不会更好。让它更优雅地失败需要更多的工作。

于 2013-02-25T22:46:58.697 回答