4 votes

sqlalchemy héritage imbriqué / relations polymorphes

J'ai un arbre qui ressemble à ceci, reflété via l'héritage polymorphe :

      A
  /   |   \
  B   C   D

Ça marche bien, comme ça :

class BaseModel(db.Model):     # Table A in diagram
    __tablename__ = "entities"

    id = db.Column(db.BigInteger, primary_key=True, nullable=False, server_default=func.nextval('guid_seq'))
    type_id = db.Column(db.SmallInteger, db.ForeignKey(EntityTypesModel.id))

    __mapper_args__ = {
        'polymorphic_identity':'entity',
        'polymorphic_on':type_id,
        'with_polymorphic':'*'
    }

class BrandModel(BaseModel):   # Table B, C, D in diagram
    __tablename__ = 'brands'

    id = db.Column(db.BigInteger, db.ForeignKey(StufffModel.id), primary_key=True, nullable=False)
    name = db.Column(db.String, nullable=False)

    __mapper_args__ = {
        'polymorphic_identity':ET_BRAND,
    }

Le problème est que j'ai besoin de refléter quelque chose de plus comme ceci :

              A
          /   |   \
          B   C   D
                /   \
                E    F

Où D est non seulement un enfant polymorphe de A mais aussi les parents polymorphes de E & F.

Il semble que je doive choisir, D peut être soit un enfant polymorphe, soit un parent - il ne peut pas être les deux.

Est-ce que j'ai des options ici ?

EDIT :

Pour terminer, j'ai fini par aplatir l'arbre pour qu'il ressemble à.. :

      A
  /   |   \   \
 B    C    E   F

D a maintenant disparu et la fonctionnalité qu'il fournissait se trouve dans les enfants (E & F). Je vais probablement faire des parties communes un mixin ou quelque chose comme ça.

C'est dommage, mais je n'ai pas pu consacrer plus de temps à cette question particulière.

5voto

van Points 18052

Vous pouvez certainement le faire. Le code ci-dessous utilise la fonction declarative_base mais il montre un modèle de configuration qui fonctionne. D est à la fois un parent et un enfant grâce à l'héritage des classes. Cependant, le polymorphic_identity est stocké uniquement au niveau supérieur. Assurez-vous que vous avez mis en place toutes les clés étrangères et les héritages de classe appropriés.

*Remarque : votre exemple définit le type_id comme numérique, mais les valeurs semblent être des chaînes de caractères.

Base = declarative_base(cls=_BaseMixin)
Base.query = session.query_property()

class BaseModel(Base):
    __tablename__ = 'entities'
    id = Column(Integer, primary_key=True)
    #type_id = Column(Integer, nullable=False)
    type_id = Column(String, nullable=False)
    __mapper_args__ = {
        'polymorphic_identity': 'entity',
        'polymorphic_on':type_id,
        'with_polymorphic':'*'
    }

class ModelB(BaseModel):
    __tablename__ = 'modelB'
    __mapper_args__ = {'polymorphic_identity': 'modelB'}
    id = Column(Integer, ForeignKey('entities.id'), primary_key=True)
    name = Column(String, nullable=False)

class ModelC(BaseModel):
    __tablename__ = 'modelC'
    __mapper_args__ = {'polymorphic_identity': 'modelC'}
    id = Column(Integer, ForeignKey('entities.id'), primary_key=True)
    name = Column(String, nullable=False)

class ModelD(BaseModel):
    __tablename__ = 'modelD'
    __mapper_args__ = {'polymorphic_identity': 'modelD'}
    id = Column(Integer, ForeignKey('entities.id'), primary_key=True)
    name = Column(String, nullable=False)

class ModelE(ModelD):
    __tablename__ = 'modelE'
    __mapper_args__ = {'polymorphic_identity': 'modelE'}
    id = Column(Integer, ForeignKey('entities.id'), ForeignKey('modelD.id'), primary_key=True)
    name = Column(String, nullable=False)

class ModelF(ModelD):
    __tablename__ = 'modelF'
    __mapper_args__ = {'polymorphic_identity': 'modelF'}
    id = Column(Integer, ForeignKey('entities.id'), ForeignKey('modelD.id'), primary_key=True)
    name = Column(String, nullable=False)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X