SQLAlchemy ORM - Création de relations

Cette session décrit la création d'une autre table liée à celle déjà existante dans notre base de données. La table clients contient les données de base des clients. Nous devons maintenant créer un tableau des factures qui peut avoir n'importe quel nombre de factures appartenant à un client. Il s'agit d'un cas de relations une à plusieurs.

En utilisant déclarative, nous définissons cette table avec sa classe mappée, Factures comme indiqué ci-dessous -

from sqlalchemy import create_engine, ForeignKey, Column, Integer, String
engine = create_engine('sqlite:///sales.db', echo = True)
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
from sqlalchemy.orm import relationship

class Customer(Base):
   __tablename__ = 'customers'

   id = Column(Integer, primary_key = True)
   name = Column(String)
   address = Column(String)
   email = Column(String)

class Invoice(Base):
   __tablename__ = 'invoices'
   
   id = Column(Integer, primary_key = True)
   custid = Column(Integer, ForeignKey('customers.id'))
   invno = Column(Integer)
   amount = Column(Integer)
   customer = relationship("Customer", back_populates = "invoices")

Customer.invoices = relationship("Invoice", order_by = Invoice.id, back_populates = "customer")
Base.metadata.create_all(engine)

Cela enverra une requête CREATE TABLE au moteur SQLite comme ci-dessous -

CREATE TABLE invoices (
   id INTEGER NOT NULL,
   custid INTEGER,
   invno INTEGER,
   amount INTEGER,
   PRIMARY KEY (id),
   FOREIGN KEY(custid) REFERENCES customers (id)
)

Nous pouvons vérifier qu'une nouvelle table est créée dans sales.db à l'aide de l'outil SQLiteStudio.

La classe Invoices applique la construction ForeignKey sur l'attribut custid. Cette directive indique que les valeurs de cette colonne doivent être contraintes à être des valeurs présentes dans la colonne id de la table des clients. Il s'agit d'une caractéristique essentielle des bases de données relationnelles, et c'est le «ciment» qui transforme une collection non connectée de tables pour avoir de riches relations qui se chevauchent.

Une deuxième directive, appelée relation (), indique à l'ORM que la classe Invoice doit être liée à la classe Customer à l'aide de l'attribut Invoice.customer. La relation () utilise les relations de clé étrangère entre les deux tables pour déterminer la nature de ce lien, en déterminant qu'il est multiple à un.

Une directive de relation () supplémentaire est placée sur la classe mappée Customer sous l'attribut Customer.invoices. Le paramètre relation.back_populates est assigné pour faire référence aux noms d'attributs complémentaires, de sorte que chaque relation () puisse prendre une décision intelligente sur la même relation exprimée en sens inverse. D'un côté, Invoices.customer fait référence à l'instance Invoices, et de l'autre côté, Customer.invoices fait référence à une liste d'instances Clients.

La fonction de relation fait partie de l'API de relation du package ORM SQLAlchemy. Il fournit une relation entre deux classes mappées. Cela correspond à une relation parent-enfant ou table associative.

Voici les modèles de relation de base trouvés -

Un à plusieurs

Une relation un à plusieurs fait référence au parent à l'aide d'une clé étrangère sur la table enfant. relation () est ensuite spécifiée sur le parent, comme faisant référence à une collection d'éléments représentés par l'enfant. Le paramètre relation.back_populates est utilisé pour établir une relation bidirectionnelle en un-à-plusieurs, où le côté «inverse» est un plusieurs à un.

Plusieurs à un

D'autre part, la relation plusieurs à un place une clé étrangère dans la table parent pour faire référence à l'enfant. relation () est déclarée sur le parent, où un nouvel attribut de maintien scalaire sera créé. Ici encore, le paramètre Relationship.back_populates est utilisé pour Bidirectionalbehaviour.

Un par un

Une relation un à un est essentiellement une relation bidirectionnelle par nature. L'indicateur uselist indique le placement d'un attribut scalaire au lieu d'une collection du côté «plusieurs» de la relation. Pour convertir un-à-plusieurs en un type de relation un-à-un, définissez le paramètre uselist sur false.

Plusieurs à plusieurs

La relation plusieurs à plusieurs est établie en ajoutant une table d'association liée à deux classes en définissant des attributs avec leurs clés étrangères. Il est indiqué par l'argument secondaire de la relation (). Habituellement, la table utilise l'objet MetaData associé à la classe de base déclarative, afin que les directives ForeignKey puissent localiser les tables distantes avec lesquelles se lier. Le paramètre Relationship.back_populates pour chaque relation () établit une relation bidirectionnelle. Les deux côtés de la relation contiennent une collection.