52 votes

Héritage SQLAlchemy

Je suis un peu confus au sujet de l'héritage sous sqlalchemy, au point que je ne suis même pas sûr du type d'héritage (table simple, table jointe, concret) que je devrais utiliser ici. J'ai une classe de base avec certaines informations qui sont partagées entre les sous-classes, et certaines données qui sont complètement séparées. Parfois, je veux des données de toutes les classes, et parfois seulement des sous-classes. Voici un exemple :

class Building:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class Commercial(Building):
    def __init__(self, x, y, business):
        Building.__init__(self, x, y)
        self.business = business

class Residential(Building):
    def __init__(self, x, y, numResidents):
        Building.__init__(self, x, y, layer)
        self.numResidents = numResidents

Comment puis-je convertir cela en SQLAlchemy en utilisant le déclaratif ? Comment, alors, pourrais-je demander quels bâtiments sont à l'intérieur de x>5 y y>3 ? Ou quels bâtiments résidentiels n'ont qu'un seul résident ?

84voto

Ants Aasma Points 22921

Le choix de la manière de représenter l'héritage est principalement une question de conception de base de données. Pour des raisons de performance, l'héritage par une seule table est généralement le meilleur. Du point de vue de la conception de la base de données, l'héritage par tables jointes est préférable. L'héritage par table jointe vous permet d'avoir des clés étrangères aux sous-classes appliquées par la base de données, il est beaucoup plus simple d'avoir des contraintes non nulles pour les champs des sous-classes. L'héritage de table concret est en quelque sorte le pire des deux mondes.

La configuration de l'héritage d'une seule table avec le déclaratif ressemble à ceci :

class Building(Base):
    __tablename__ = 'building'
    id = Column(Integer, primary_key=True)
    building_type = Column(String(32), nullable=False)
    x = Column(Float, nullable=False)
    y = Column(Float, nullable=False)
    __mapper_args__ = {'polymorphic_on': building_type}

class Commercial(Building):
    __mapper_args__ = {'polymorphic_identity': 'commercial'}
    business = Column(String(50))

class Residential(Building):
    __mapper_args__ = {'polymorphic_identity': 'residential'}
    num_residents = Column(Integer)

Pour que l'héritage de la table soit joint, vous devrez ajouter

__tablename__ = 'commercial'
id = Column(None, ForeignKey('building.id'), primary_key=True)

aux sous-classes.

Les requêtes sont pratiquement les mêmes dans les deux approches :

# buildings that are within x>5 and y>3
session.query(Building).filter((Building.x > 5) & (Building.y > 3))
# Residential buildings that have only 1 resident
session.query(Residential).filter(Residential.num_residents == 1)

Pour contrôler les champs qui sont chargés, vous pouvez utiliser la fonction query.with_polymorphic() méthode.

La chose la plus importante à laquelle vous devez penser lorsque vous utilisez l'héritage pour le mappage des données est de savoir si vous avez réellement besoin de l'héritage ou si vous pouvez vous contenter de l'agrégation. L'héritage sera un problème si vous devez changer le type d'un bâtiment, ou si vos bâtiments peuvent avoir des aspects commerciaux et résidentiels. Dans ces cas, il est généralement préférable que les aspects commerciaux et résidentiels soient des objets liés.

12voto

adam Points 1848

La solution d'Ants Aasma est beaucoup plus élégante, mais si vous gardez intentionnellement vos définitions de classes séparées de vos définitions de tables, vous devez faire correspondre vos classes à vos tables avec la fonction mapper. Après avoir défini vos classes, vous devez définir vos tables :

building = Table('building', metadata,
    Column('id', Integer, primary_key=True),
    Column('x', Integer),
    Column('y', Integer),
)
commercial = Table('commercial', metadata,
    Column('building_id', Integer, ForeignKey('building.id'), primary_key=True),
    Column('business', String(50)),
)
residential = Table('residential', metadata,
    Column('building_id', Integer, ForeignKey('building.id'), primary_key=True),
    Column('numResidents', Integer),
)

Ensuite, vous pouvez faire correspondre les tables aux classes :

mapper(Building, building)
mapper(Commercial, commercial, inherits=Building, polymorphic_identity='commercial')
mapper(Residential, residential, inherits=Building, polymorphic_identity='residential')

Ensuite, interagissez avec les classes exactement de la même manière que celle décrite par Ants Aasma.

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