简体   繁体   English

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

[英]Get sqlalchemy base class object instead of children

I have three classes in my model, which one class inherited by the other two: 我的模型中有三个类,其中一个类由另外两个继承:

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'
    }

So, when I execute session.query(Item).all() I get a list that includes both Note and Task objects, but I don't want that, I want my objects to be the instance of Item class and just have id , title , type , not those extra fields. 所以,当我执行session.query(Item).all()我得到一个包含NoteTask对象的列表,但我不希望这样,我希望我的对象是Item类的实例,只是有idtitletype ,而不是那些额外的字段。 how should I write the query? 我该怎么写这个查询?

to clarify more, currently, I get: 澄清更多,目前,我得到:

[
     <models.Note object at 0x7f25ac3ffe80>,
     <models.Task object at 0x7f25ac3ffe80>,
     <models.Task object at 0x7f25ac3ffe80>,
     ...
]

But I want to get: 但我想得到:

[
    <models.Item object at 0x000000000000>,
    <models.Item object at 0x000000000000>,
    <models.Item object at 0x000000000000>,
    ...
]

NOTE: This may be problematic in a multi-threaded application. 注意:这在多线程应用程序中可能存在问题。

You could use a context manager to temporarily block the polymorphism: 您可以使用上下文管理器暂时阻止多态:

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>]

Something to be mindful of and as noted in the comments in my example, if the identity of the object is already referenced in the Identity Map , then you will get back whatever type is held in there, regardless of the class that you query on. 需要注意的事项,如我的示例中的注释中所述,如果对象的标识已在Identity Map中引用,那么无论您查询哪个类,都将返回其中的任何类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM