SQLAlchemy introspect тип столбца с наследованием

Учитывая этот код (и используя SQLAlchemy 0.7.7):

class Document(Base):
    __tablename__ = 'document'
    __table_args__ = {
        'schema': 'app'
    }

    id = Column(types.Integer, primary_key=True)
    nom = Column(types.Unicode(256), nullable=False)
    date = Column(types.Date())

    type_document = Column(types.Enum('arrete', 'photographie',
        name='TYPES_DOCUMENT_ENUM'))
    __mapper_args__ = {'polymorphic_on': type_document}

class Arrete(Document):
    __tablename__ = 'arrete'
    __table_args__ = {
        'schema': 'app'
    }
    __mapper_args__ = {'polymorphic_identity': 'arrete'}

    id = Column(types.Integer, ForeignKey('app.document.id'), primary_key=True)
    numero_arrete = Column(types.Integer)
    date_arrete = Column(types.Date())

Я могу легко понять тип столбца для столбца, определенного в классе Arrete, с помощью:

Arrete.__table__.c['date_arrete'].type

Но это не работает, если я хочу получить через класс Arrete столбец, определенный в классе Document. (KeyError, если я пытаюсь получить доступ к c['date']).

Есть ли способ получить тип столбца, независимо от того, определен ли столбец в конечном классе или в одном из его родительских?

Ответ 1

ORM позволяет вам определять классы в шаблоне наследования, которые соответствуют JOIN из двух таблиц. Эта структура является полным сервисом и также может использоваться для поиска основных вещей, таких как типы атрибутов в столбцах, в значительной степени непосредственно:

type = Arrete.date.property.columns[0].type

Обратите внимание, что это в основном то же самое, что подход к тащиться через __bases__, за исключением того, что вы позволяете механике нормального класса Python выполнять работу.

Ответ 2

Вы можете изучить базовые классы...

def find_type(class_, colname):
    if hasattr(class_, '__table__') and colname in class_.__table__.c:
        return class_.__table__.c[colname].type
    for base in class_.__bases__:
        return find_type(base, colname)
    raise NameError(colname)

print find_type(Arrete, 'date_arrete')
print find_type(Arrete, 'date')

Ответ 3

Вам нужна специальная директива абстрактная специальная директива или шаблон mixin.

Для mixin вы должны использовать что-то вроде этого:

class MyMixin(object):
    __tablename__ = 'document'
    __table_args__ = {
        'schema': 'app'
    }

    id = Column(types.Integer, primary_key=True)
    nom = Column(types.Unicode(256), nullable=False)
    date = Column(types.Date())

class Arrete(MyMixin, Base):
    __tablename__ = 'arrete'

    __mapper_args__ = {'polymorphic_identity': 'arrete'}

    foreign_id = Column(types.Integer, ForeignKey('app.document.id'), primary_key=True)
    numero_arrete = Column(types.Integer)
    date_arrete = Column(types.Date())


class Document(MyMixin, Base):
    __tablename__ = 'Document'
    type_document = Column(types.Enum('arrete', 'photographie',
        name='TYPES_DOCUMENT_ENUM'))
    __mapper_args__ = {'polymorphic_on': type_document}

Общие вещи идут в mixin, не разделяемые вещи в подклассах.