获取sqlalchemy基类对象而不是子对象

Meh*_*far 7 python inheritance sqlalchemy python-3.x

我的模型中有三个类,其中一个类由另外两个继承:

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'
    }
Run Code Online (Sandbox Code Playgroud)

所以,当我执行session.query(Item).all()我得到既包括列表NoteTask对象,但我不希望这样,我希望我的对象是实例Item类,只是有id,title,type,而不是那些额外的字段.我该怎么写这个查询?

澄清更多,目前,我得到:

[
     <models.Note object at 0x7f25ac3ffe80>,
     <models.Task object at 0x7f25ac3ffe80>,
     <models.Task object at 0x7f25ac3ffe80>,
     ...
]
Run Code Online (Sandbox Code Playgroud)

但我想得到:

[
    <models.Item object at 0x000000000000>,
    <models.Item object at 0x000000000000>,
    <models.Item object at 0x000000000000>,
    ...
]
Run Code Online (Sandbox Code Playgroud)

Sup*_*oot 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>]
Run Code Online (Sandbox Code Playgroud)

需要注意的是,正如我的示例中的注释中所指出的,如果对象的标识已在 Identity Map中引用,那么无论您查询哪个类,您都将返回其中保存的任何类型。

  • 这似乎可能会在多线程程序中带来一些风险,因为它会就地修改映射器。 (3认同)