Получите объект базового класса sqlalchemy вместо детей - PullRequest
0 голосов
/ 24 ноября 2018

В моей модели три класса, один из которых унаследован двумя другими:

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

1 Ответ

0 голосов
/ 25 ноября 2018

ПРИМЕЧАНИЕ. Это может быть проблематично в многопоточном приложении.

Вы можете использовать менеджер контекста для временной блокировки полиморфизма:

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

Что-топомнить и, как отмечалось в комментариях к моему примеру, если идентификатор объекта уже указан в Identity Map , то вы получите тот тип, который там содержится, независимо от классачто вы запрашиваете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...