Возможен ли многоуровневый полиморфизм в SQLAlchemy? - PullRequest
9 голосов
/ 18 мая 2010

Возможно ли иметь многоуровневый полиморфизм в SQLAlchemy? Вот пример:

class Entity(Base):
    __tablename__ = 'entities'
    id = Column(Integer, primary_key=True)
    created_at = Column(DateTime, default=datetime.utcnow, nullable=False)
    entity_type = Column(Unicode(20), nullable=False)
    __mapper_args__ = {'polymorphic_on': entity_type}

class File(Entity):
    __tablename__ = 'files'
    id = Column(None, ForeignKey('entities.id'), primary_key=True)
    filepath = Column(Unicode(255), nullable=False)
    file_type = Column(Unicode(20), nullable=False)
    __mapper_args__ = {'polymorphic_identity': u'file', 'polymorphic_on': file_type)

class Image(File):
    __mapper_args__ = {'polymorphic_identity': u'image'}
    __tablename__ = 'images'
    id = Column(None, ForeignKey('files.id'), primary_key=True)
    width = Column(Integer)
    height = Column(Integer)

Когда я вызываю Base.metadata.create_all(), SQLAlchemy вызывает следующую ошибку:

IntegrityError: (IntegrityError) entities.entity_type may not be NULL`.

Эта ошибка исчезнет, ​​если я удалю модель Image и клавишу polymorphic_on в File.

Что дает?

Ответы [ 2 ]

13 голосов
/ 18 мая 2010

Да . Проблема с вашим кодом заключается в том, что вы делаете Image типом файла, когда вы должны стремиться к головке дерева, делая Image типом сущности.

Пример:

from sqlalchemy import (Table, Column, Integer, String, create_engine,
    MetaData, ForeignKey)
from sqlalchemy.orm import mapper, create_session
from sqlalchemy.ext.declarative import declarative_base

e = create_engine('sqlite:////tmp/foo.db', echo=True)
Base = declarative_base(bind=e)

class Employee(Base):
    __tablename__ = 'employees'

    employee_id = Column(Integer, primary_key=True)
    name = Column(String(50))
    type = Column(String(30), nullable=False)

    __mapper_args__ = {'polymorphic_on': type}

    def __init__(self, name):
        self.name = name

class Manager(Employee):
    __tablename__ = 'managers'
    __mapper_args__ = {'polymorphic_identity': 'manager'}

    employee_id = Column(Integer, ForeignKey('employees.employee_id'),
        primary_key=True)
    manager_data = Column(String(50))

    def __init__(self, name, manager_data):
        super(Manager, self).__init__(name)
        self.manager_data = manager_data

class Owner(Manager):
    __tablename__ = 'owners'
    __mapper_args__ = {'polymorphic_identity': 'owner'}

    employee_id = Column(Integer, ForeignKey('managers.employee_id'),
        primary_key=True)
    owner_secret = Column(String(50))

    def __init__(self, name, manager_data, owner_secret):
        super(Owner, self).__init__(name, manager_data)
        self.owner_secret = owner_secret

Base.metadata.drop_all()
Base.metadata.create_all()

s = create_session(bind=e, autoflush=True, autocommit=False)    
o = Owner('nosklo', 'mgr001', 'ownerpwd')
s.add(o)
s.commit()
2 голосов
/ 25 января 2017

Невозможно (см. SQL ALchemy doc ):

В настоящее время может быть установлен только один столбец дискриминатора, обычно для самого базового класса в иерархии. «Каскадные» полиморфные столбцы пока не поддерживаются.

Таким образом, вы должны следовать предложению @nosklo, чтобы изменить свою модель наследия.

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