Dan*_* S. 5 python sqlalchemy python-3.x
我正在尝试使用 SQLAlchemy 实现单表继承。根据官方的 SQLAlchemy 文档(此处:official docs),分配单个多态身份的方法如下:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'employee',
'polymorphic_on':type
}
Run Code Online (Sandbox Code Playgroud)
我想为一个班级分配多个身份。例如:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'employee',
'polymorphic_on':type
}
class Manager(Employee):
manager_name = Column(String(30))
company_id = Column(ForeignKey('company.id'))
company = relationship("Company", back_populates="managers")
__mapper_args__ = {
'polymorphic_identity': ['manager', 'ceo'],
}
Run Code Online (Sandbox Code Playgroud)
请注意以下行:
'polymorphic_identity': ['manager', 'ceo']
Run Code Online (Sandbox Code Playgroud)
这条线是不可能的(不幸的是)。
我想知道是否有任何方法可以将多个多态身份分配给单个类。不幸的是,我在文档中找不到任何这样的例子。
小智 5
我知道这早就有人回答了,但这是另一种选择。
的polymorphic_on也可以取一个case根据该文档
https://docs.sqlalchemy.org/en/13/orm/mapping_api.html#sqlalchemy.orm.mapper.params.polymorphic_on
因此,每个类仍然只有 1 个,polymorphic_identity但polymorphic_on您可以将多个值映射到相同的身份。
在您的情况下,它可能看起来像:
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String(50))
type = Column(String(50))
__mapper_args__ = {
'polymorphic_identity':'employee',
"polymorphic_on":case(
[
(type == "manager", "manager"),
(type == "ceo", "manager"),
],
else_="employee"
)
}
class Manager(Employee):
manager_name = Column(String(30))
company_id = Column(ForeignKey('company.id'))
company = relationship("Company", back_populates="managers")
__mapper_args__ = {
'polymorphic_identity': 'manager',
}
Run Code Online (Sandbox Code Playgroud)
我还没有尝试过in或 SQLAlchemy 的.in_
该代码将不起作用,因为类polymorphic_identity的 被用作字典键。[] in {}因此,出于与引发 a相同的原因TypeError,您的代码也是如此。
执行此类操作的通常方法是创建一个CEO类,该类是该类的子类,Manager然后该类将能够拥有自己的polymorphic_identity以及Mapper. 但除此之外,您可以polymorphic_identity为给定的类创建第二个(但这有点hacky)。
继承自的每个类都Base引用相同的polymorphic_map,这只是一个dict:
from sqlalchemy.orm import class_mapper
emp_mapper = class_mapper(Employee)
mgr_mapper = class_mapper(Manager)
print(type(emp_mapper.polymorphic_map)) # <class 'dict'>
print(emp_mapper.polymorphic_map is mgr_mapper.polymorphic_map) # True
Run Code Online (Sandbox Code Playgroud)
将polymorphic_mapa 映射polymorphic_identity到 a Mapper,以便当从数据库中获取给定行时,分配为该列的列的值polymorphic_identity可用于获取应用于表示该数据的类。例如,仅定义您的Employee类后,polymorphic_map看起来像这样:{'employee': <Mapper at 0x1b1eafcac50; Employee>}。在用as定义Manager类之后,它看起来像这样:'manager'polymorphic_identity{'employee': <Mapper at 0x25d10b19cf8; Employee>, 'manager': <Mapper at 0x25d0fdbd4e0; Manager>}
我将创建一些测试数据(我必须删除对公司表的所有引用 - 请参阅MCVE):
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
s = Session()
engineer = Employee(name='engineer')
manager1 = Manager(name='manager1')
manager2 = Manager(name='manager2')
s.add_all([engineer, manager1, manager2])
s.commit()
print(s.query(Employee).all()) # [<__main__.Employee object at 0x000001E5E54A0550>, <__main__.Manager object at 0x000001E5E54A0CF8>, <__main__.Manager object at 0x000001E5E54A0D68>]
print(s.query(Manager).all()) # [<__main__.Manager object at 0x000001E5E54A0CF8>, <__main__.Manager object at 0x000001E5E54A0D68>]
Run Code Online (Sandbox Code Playgroud)
现在,让我们将经理晋升为首席执行官:
manager1.type = 'ceo'
s.commit()
Run Code Online (Sandbox Code Playgroud)
这会发出警告:
SAWarning: Flushing object <Manager at 0x1e5e54a0cf8> with incompatible polymorphic identity 'ceo'; the object may not refresh and/or load correctly (this warning may be suppressed after 10 occurrences)
Run Code Online (Sandbox Code Playgroud)
但我们将忽略这一点并尝试查询员工表:
print(s.query(Employee).all())
Run Code Online (Sandbox Code Playgroud)
加薪:
Traceback (most recent call last):
File "C:\Users\peter_000\.virtualenvs\test-_0Fb_hDQ\lib\site-packages\sqlalchemy\orm\loading.py", line 721, in configure_subclass_mapper
sub_mapper = mapper.polymorphic_map[discriminator]
KeyError: 'ceo'
Run Code Online (Sandbox Code Playgroud)
因此,typemanager1 的列现在具有一个不存在于 中的值polymorphic_map,并且我们收到一个关键错误。由于我们只对代表为 a 的 CEO 感兴趣,Manager因此我们可以手动添加一个条目,将polymorphic_map关键“ceo”与该类相关Mapper联Manager。例如:
mgr_mapper.polymorphic_map['ceo'] = mgr_mapper
Run Code Online (Sandbox Code Playgroud)
现在让我们再次查询员工表:
print(s.query(Employee).all()) # [<__main__.Employee object at 0x0000020EE7320550>, <__main__.Manager object at 0x0000020EE7320CF8>, <__main__.Manager object at 0x0000020EE7320D68>]
Run Code Online (Sandbox Code Playgroud)
请注意,它现在再次打印两个管理器对象。
Mapper免责声明:在for内部,它维护对类的 (即)Manager的引用,因此我们的键指向引用 a of的映射器。我提到这一点是因为虽然所有这些在本示例中都运行良好,但我不知道这是否会导致 sqlalchemy 中的其他地方出现错误。因此,如果您在生产中使用类似的东西,请确保它经过充分测试。polymorphic_identity'manager'ceopolymorphic_mappolymorphic_identitymanager
| 归档时间: |
|
| 查看次数: |
3113 次 |
| 最近记录: |