SQLAlchemy ORM - Aufbau einer Beziehung

In dieser Sitzung wird die Erstellung einer weiteren Tabelle beschrieben, die sich auf eine bereits vorhandene Tabelle in unserer Datenbank bezieht. Die Kundentabelle enthält Stammdaten von Kunden. Wir müssen jetzt eine Rechnungstabelle erstellen, die eine beliebige Anzahl von Rechnungen eines Kunden enthalten kann. Dies ist ein Fall von einer bis vielen Beziehungen.

Mit deklarativ definieren wir diese Tabelle zusammen mit der zugeordneten Klasse "Rechnungen" wie unten angegeben -

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)

Dadurch wird eine CREATE TABLE-Abfrage wie folgt an die SQLite-Engine gesendet:

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

Mit Hilfe des SQLiteStudio-Tools können wir überprüfen, ob eine neue Tabelle in sales.db erstellt wurde.

Die Invoices-Klasse wendet das ForeignKey-Konstrukt auf das custid-Attribut an. Diese Anweisung gibt an, dass die Werte in dieser Spalte auf Werte beschränkt werden sollten, die in der Spalte id in der Kundentabelle vorhanden sind. Dies ist ein Kernmerkmal relationaler Datenbanken und der „Klebstoff“, der die nicht verbundene Sammlung von Tabellen in reich überlappende Beziehungen umwandelt.

Eine zweite Anweisung, die als Relationship () bezeichnet wird, teilt dem ORM mit, dass die Invoice-Klasse mit dem Attribut Invoice.customer mit der Customer-Klasse verknüpft werden soll. Die Beziehung () verwendet die Fremdschlüsselbeziehungen zwischen den beiden Tabellen, um die Art dieser Verknüpfung zu bestimmen und festzustellen, ob es sich um viele zu eins handelt.

Eine zusätzliche Beziehungsanweisung () wird für die vom Kunden zugeordnete Klasse unter dem Attribut Customer.invoices platziert. Der Parameter Relationship.back_populate wird zugewiesen, um auf die komplementären Attributnamen zu verweisen, sodass jede Beziehung () eine intelligente Entscheidung über dieselbe Beziehung treffen kann, wie sie umgekehrt ausgedrückt wird. Auf der einen Seite bezieht sich Invoices.customer auf die Instanz Invoices, und auf der anderen Seite bezieht sich Customer.invoices auf eine Liste von Kundeninstanzen.

Die Beziehungsfunktion ist Teil der Beziehungs-API des SQLAlchemy ORM-Pakets. Es bietet eine Beziehung zwischen zwei zugeordneten Klassen. Dies entspricht einer Eltern-Kind- oder assoziativen Tabellenbeziehung.

Im Folgenden sind die grundlegenden gefundenen Beziehungsmuster aufgeführt:

Eins zu viele

Eine Eins-zu-Viele-Beziehung bezieht sich auf Eltern mit Hilfe eines Fremdschlüssels in der untergeordneten Tabelle. beziehung () wird dann auf dem übergeordneten Element als Verweis auf eine Sammlung von Elementen angegeben, die vom untergeordneten Element dargestellt werden. Der Parameter ratio.back_populate wird verwendet, um eine bidirektionale Beziehung in Eins-zu-Viele herzustellen, wobei die "umgekehrte" Seite viele-zu-Eins ist.

Viele zu einem

Auf der anderen Seite platziert die Beziehung "Viele zu Eins" einen Fremdschlüssel in der übergeordneten Tabelle, um auf das untergeordnete Element zu verweisen. beziehung () wird auf dem übergeordneten Element deklariert, wo ein neues skalarhaltendes Attribut erstellt wird. Auch hier wird der Parameter ratio.back_populate für das bidirektionale Verhalten verwendet.

Eins zu eins

Eine Eins-zu-Eins-Beziehung ist im Wesentlichen eine bidirektionale Beziehung. Das Uselist-Flag zeigt die Platzierung eines skalaren Attributs anstelle einer Sammlung auf der "vielen" Seite der Beziehung an. Setzen Sie den uselist-Parameter auf false, um eine Eins-zu-Viele-Beziehung in eine Eins-zu-Eins-Beziehung umzuwandeln.

Viel zu viel

Die Beziehung "Viele zu Viele" wird hergestellt, indem eine Zuordnungstabelle hinzugefügt wird, die sich auf zwei Klassen bezieht, indem Attribute mit ihren Fremdschlüsseln definiert werden. Es wird durch das sekundäre Argument zu Beziehung () angezeigt. Normalerweise verwendet die Tabelle das MetaData-Objekt, das der deklarativen Basisklasse zugeordnet ist, sodass die ForeignKey-Anweisungen die entfernten Tabellen finden können, mit denen eine Verknüpfung hergestellt werden soll. Der Parameter education.back_populated für jede Beziehung () erstellt eine bidirektionale Beziehung. Beide Seiten der Beziehung enthalten eine Sammlung.