获取 sqlalchemy 基类对象而不是子对象
Posted
技术标签:
【中文标题】获取 sqlalchemy 基类对象而不是子对象【英文标题】:Get sqlalchemy base class object instead of children 【发布时间】:2018-11-24 12:10:52 【问题描述】:我的模型中有三个类,其中一个类被另外两个继承:
class Item(Base):
__tablename__ = 'item'
id = Column(Integer, primary_key=True)
title = Column(Unicode(300))
type = Column(Unicode(50))
__mapper_args__ =
'polymorphic_on': type
class Note(Item):
__tablename__ = 'note'
id = Column(Integer, ForeignKey('item.id'), primary_key=True)
extra = Column(Text)
__mapper_args__ =
'polymorphic_identity': 'note'
class Task(Item):
__tablename__ = 'task'
id = Column(Integer, ForeignKey('item.id'), primary_key=True)
another_extra = Column(Text)
__mapper_args__ =
'polymorphic_identity': 'task'
所以,当我执行 session.query(Item).all()
时,我得到一个包含 Note
和 Task
对象的列表,但我不希望这样,我希望我的对象是 Item
类的实例,并且只是有id
、title
、type
,而不是那些额外的字段。我应该如何编写查询?
为了澄清更多,目前,我得到:
[
<models.Note object at 0x7f25ac3ffe80>,
<models.Task object at 0x7f25ac3ffe80>,
<models.Task object at 0x7f25ac3ffe80>,
...
]
但我想得到:
[
<models.Item object at 0x000000000000>,
<models.Item object at 0x000000000000>,
<models.Item object at 0x000000000000>,
...
]
【问题讨论】:
仅仅query for those specific columns 并得到一个命名元组就足够了吗?还是您绝对需要回复Item
?
@SuperShoot 我需要它们成为Item
类的实例。顺便谢谢你的喜欢。
不确定它是否会帮助您,但我注意到如果您删除多态身份,它会按预期工作。
代码不能为我运行(得到:“没有定义这样的 polymorphic_identity '类型'”)(?)但根据我认为just_item = with_polymorphic(Item, [Note, Task])
的文档,然后是:session.query(just_item).all()
可能工作?见:docs.sqlalchemy.org/en/latest/orm/inheritance_loading.html
@HansBouwmeester with_polymorphic(Item, [Note, Task])
确保在查询基类时,属于类列表(本例中为Note
和Task
)的属性被预先加载,以便生成的对象以后不必延迟加载属性值。从该查询返回的对象仍将是 Note
和 Task
对象。
【参考方案1】:
注意:这在多线程应用程序中可能会出现问题。
您可以使用上下文管理器来临时阻止多态性:
from contextlib import contextmanager
from sqlalchemy import inspect
@contextmanager
def no_poly(class_):
mapper = inspect(class_).mapper
polycol = mapper.polymorphic_on
mapper.polymorphic_on = None
yield class_
mapper.polymorphic_on = polycol
Base.metadata.drop_all(engine)
Base.metadata.create_all(engine)
task = Task(title='Task Title', another_extra='something')
s = Session()
s.add(task)
s.commit()
# opening a new session as if the pk already exists in the
# identity map it will return whatever type that pk is
# pointing at.
s = Session()
with no_poly(Item) as class_:
inst = s.query(class_).all()
print(inst) # [<__main__.Item object at 0x000001443685DDD8>]
s = Session() # new session again.
inst = s.query(Item).all()
print(inst) # [<__main__.Task object at 0x00000144368770B8>]
需要注意的一点,正如我的示例中的 cmets 中所指出的,如果对象的标识已经在 Identity Map 中引用,那么您将取回其中保存的任何类型,无论该类是什么你查询。
【讨论】:
这看起来可能会给多线程程序带来一些风险,因为它会修改映射器。 IIja 是正确的,我真的不想修改mapper
,我只是在寻找查询或__mapper_args__
以某种方式工作。
@IljaEverilä 你知道如何实现这一目标吗?
是的,它不是线程安全的。我会在答案中注明。在这种情况下,这是先决条件吗?以上是关于获取 sqlalchemy 基类对象而不是子对象的主要内容,如果未能解决你的问题,请参考以下文章
获取时间戳而不是日期时间对象,sqlalchemy python 2.7