2013-06-04 3 views
2

j'ai un arbre qui ressemble à ceci, qui se traduit par héritage polymorphes:sqlalchemy héritage imbriqué/relations polymorphes

 A 
/ | \ 
    B C D 

Cela fonctionne très bien, comme:

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 je dois réfléchir quelque chose comme ceci:

   A 
     / | \ 
      B C D 
       / \ 
       E F 

Où D est non seulement un enfant de a polymorphes mais Il semble que je doive choisir, D peut être un enfant polymorphe ou peut être un parent - il ne peut pas être les deux.

Ai-je des options ici?

EDIT:

Juste pour attacher ceci, je fini par aplatir l'arbre de sorte qu'il ressemble:

 A 
/ | \ \ 
B C E F 

D est maintenant disparu et la fonctionnalité qu'il a fournies sont les enfants (E & F). Je vais probablement faire des parties communes un mélange ou quelque chose.

Dommage mais je ne pouvais pas passer plus de temps sur ce problème particulier.

Répondre

3

Vous pouvez certainement le faire. Le code ci-dessous utilise le declarative_base, mais montre la configuration du modèle qui fonctionne. D La classe est à la fois un parent et un enfant utilisant l'héritage de classe. Cependant, le polymorphic_identity est stocké uniquement au niveau supérieur. Assurez-vous de disposer de toutes les clés étrangères et de tous les héritages de classe appropriés.

*. Remarque: vous par exemple définit comme type_id numérique, mais les valeurs semblent être des chaînes *

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) 
+0

donc cela ressemble, il est hors de cochon soutenant la colonne discriminante type_id sur modela. En réalité, les modèles D E F sont discriminés par une autre colonne - peut-être l'appeler type_inner_id. Cependant, ModelD doit rester polymorphe par rapport à ModelA sur la colonne type_id. – amirpc

+0

Je crois que c'est la façon qui a du sens, et certainement ne l'appellerait pas piggy backing. Génial, vous avez trouvé une solution acceptable pour vous. – van

+0

Comment pouvez-vous maintenant lier un ForeignKey d'une classe comme "class Ricky (Base)" vers la table "entities" dans BaseModel (Base)? ça continue à me donner: sqlalchemy.exc.NoReferencedTableError –