SQLAlchemy
The Database Toolkit for Python
Das Datenbank-Toolkit für Python
  • Startseite
  • Funktionen
    • Philosophieerklärung
    • Funktionsübersicht
    • Testimonials
  • Neuigkeiten
  • Dokumentation
    • Aktuelle Dokumentation (Version 2.0)

    • Dokumentation nach Version
    • Version 2.1 (Entwicklung)
    • Version 2.0
    • Version 1.4
    • Version 1.3

    • Vorträge und Tutorials
    • Übersicht veröffentlichter Inhalte
  • Community
    • Support erhalten
    • Teilnehmen
    • Entwickeln
    • Verhaltenskodex
    • Github
  • Download
    • Download
    • Aktuelle Release-Serie (2.0)
    • Wartungs-Release (1.4)
    • Entwicklungszugang
    • Lizenz
    • Versionsnummerierung
    • Release-Status
Release: 2.0.39 aktuelles Release | Release-Datum: 11. März 2025

SQLAlchemy 2.0 Dokumentation

SQLAlchemy 2.0 Dokumentation

aktuelles Release

Startseite | Diese Dokumentation herunterladen

SQLAlchemy Unified Tutorial

  • Aufbau der Konnektivität - die Engine
  • Arbeiten mit Transaktionen und der DBAPI
  • Arbeiten mit Datenbankmetadaten¶
    • Einrichtung von MetaData mit Table-Objekten
      • Komponenten von Table
      • Einfache Constraints deklarieren
      • DDL an die Datenbank senden
    • Verwendung von ORM-Deklarationsformen zur Definition von Tabellenmetadaten
      • Einrichtung einer deklarativen Basis
      • Geflaggte Klassen deklarieren
      • DDL von einer ORM-Zuordnung an die Datenbank senden
    • Tabellen-Reflektion
    • Nächste Schritte
  • Arbeiten mit Daten
  • Datenmanipulation mit der ORM
  • Arbeiten mit ORM-bezogenen Objekten
  • Weitere Lektüre

Projektversionen

  • 2.0.39

Startseite | Diese Dokumentation herunterladen

  • Vorheriges: Arbeiten mit Transaktionen und DBAPI
  • Nächstes: Arbeiten mit Daten
  • Nach oben: Startseite
    • SQLAlchemy Unified Tutorial
  • Auf dieser Seite
    • Arbeiten mit Datenbankmetadaten
      • Einrichtung von MetaData mit Table-Objekten
        • Komponenten von Table
        • Einfache Constraints deklarieren
        • DDL an die Datenbank senden
      • Verwendung von ORM-Deklarationsformen zur Definition von Tabellenmetadaten
        • Einrichtung einer deklarativen Basis
        • Geflaggte Klassen deklarieren
        • DDL von einer ORM-Zuordnung an die Datenbank senden
      • Tabellen-Reflektion
      • Nächste Schritte

SQLAlchemy 1.4 / 2.0 Tutorial

Diese Seite ist Teil des SQLAlchemy Unified Tutorial.

Vorheriges: Arbeiten mit Transaktionen und DBAPI | Nächstes: Arbeiten mit Daten

Arbeiten mit Datenbankmetadaten¶

Nachdem wir uns mit Engines und SQL-Ausführung beschäftigt haben, sind wir bereit, mit der Alchemy zu beginnen. Das zentrale Element von SQLAlchemy Core und ORM ist die SQL-Ausdruckssprache, die eine flüssige, komponierbare Konstruktion von SQL-Abfragen ermöglicht. Die Grundlage für diese Abfragen sind Python-Objekte, die Datenbankkonzepte wie Tabellen und Spalten darstellen. Diese Objekte werden kollektiv als Datenbankmetadaten bezeichnet.

Die gebräuchlichsten grundlegenden Objekte für Datenbankmetadaten in SQLAlchemy sind MetaData, Table und Column. Die folgenden Abschnitte veranschaulichen, wie diese Objekte sowohl in einem Core-orientierten als auch in einem ORM-orientierten Stil verwendet werden.

ORM-Leser, bleiben Sie dran!

Wie bei anderen Abschnitten können Core-Benutzer die ORM-Abschnitte überspringen, aber ORM-Benutzer sollten mit diesen Objekten aus beiden Perspektiven vertraut sein. Das hier diskutierte Table-Objekt wird bei Verwendung des ORM auf indirektere Weise (und auch vollständig typisiert in Python) deklariert, es gibt jedoch immer noch ein Table-Objekt innerhalb der ORM-Konfiguration.

Einrichtung von MetaData mit Table-Objekten¶

Wenn wir mit einer relationalen Datenbank arbeiten, ist die grundlegende datenhaltende Struktur in der Datenbank, aus der wir Abfragen erstellen, als Tabelle bekannt. In SQLAlchemy wird die Datenbank „Tabelle“ letztendlich durch ein Python-Objekt mit dem ähnlich benannten Namen Table dargestellt.

Um mit der SQLAlchemy Expression Language zu arbeiten, benötigen wir konstruierte Table-Objekte, die alle Datenbanktabellen darstellen, an denen wir interessiert sind. Das Table wird programmatisch konstruiert, entweder direkt durch Verwendung des Table-Konstruktors oder indirekt durch Verwendung von ORM Mapped Classes (weiter unten unter Verwendung von ORM-Deklarationsformen zur Definition von Tabellenmetadaten beschrieben). Es besteht auch die Möglichkeit, einige oder alle Tabelleninformationen aus einer vorhandenen Datenbank zu laden, was als Reflektion bezeichnet wird.

Welche Art von Ansatz auch immer verwendet wird, wir beginnen immer mit einer Sammlung, in der wir unsere Tabellen platzieren werden, die als MetaData-Objekt bekannt ist. Dieses Objekt ist im Wesentlichen eine Fassade um ein Python-Dictionary, das eine Reihe von Table-Objekten speichert, die mit ihrem String-Namen indiziert sind. Während die ORM einige Optionen anbietet, wo diese Sammlung bezogen werden kann, haben wir immer die Möglichkeit, einfach eine direkt zu erstellen, was so aussieht:

>>> from sqlalchemy import MetaData
>>> metadata_obj = MetaData()

Sobald wir ein MetaData-Objekt haben, können wir einige Table-Objekte deklarieren. Dieses Tutorial beginnt mit dem klassischen SQLAlchemy-Tutorialmodell, das eine Tabelle namens user_account hat, die beispielsweise die Benutzer einer Website speichert, und eine zugehörige Tabelle address, die E-Mail-Adressen speichert, die mit Zeilen in der user_account-Tabelle verknüpft sind. Wenn wir überhaupt keine ORM-Deklarationsmodelle verwenden, konstruieren wir jedes Table-Objekt direkt, und weisen es typischerweise einer Variablen zu, die wir verwenden werden, um uns in Anwendungscode auf die Tabelle zu beziehen.

>>> from sqlalchemy import Table, Column, Integer, String
>>> user_table = Table(
...     "user_account",
...     metadata_obj,
...     Column("id", Integer, primary_key=True),
...     Column("name", String(30)),
...     Column("fullname", String),
... )

Mit dem obigen Beispiel werden wir, wenn wir Code schreiben möchten, der sich auf die user_account-Tabelle in der Datenbank bezieht, die Python-Variable user_table verwenden, um darauf zu verweisen.

Wann erstelle ich ein MetaData-Objekt in meinem Programm?

Ein einziges MetaData-Objekt für eine gesamte Anwendung ist der häufigste Fall und wird als Modul-weite Variable an einer einzigen Stelle in einer Anwendung dargestellt, oft in einem Paket vom Typ „models“ oder „dbschema“. Es ist auch sehr üblich, dass auf das MetaData über eine ORM-zentrierte registry oder eine Deklarative Basis-Klasse zugegriffen wird, sodass dieses MetaData zwischen ORM- und Core-deklarierten Table-Objekten geteilt wird.

Es kann auch mehrere MetaData-Sammlungen geben; Table-Objekte können ohne Einschränkungen auf Table-Objekte in anderen Sammlungen verweisen. Für Gruppen von Table-Objekten, die miteinander verwandt sind, ist es jedoch in der Praxis weitaus einfacher, sie innerhalb einer einzigen MetaData-Sammlung einzurichten, sowohl aus der Perspektive ihrer Deklaration als auch aus der Perspektive der Reihenfolge, in der DDL (d. h. CREATE- und DROP-Anweisungen) gesendet werden.

Komponenten von Table¶

Wir können beobachten, dass die Table-Konstruktion, wie sie in Python geschrieben ist, eine Ähnlichkeit mit einer SQL CREATE TABLE-Anweisung aufweist; beginnend mit dem Tabellennamen, gefolgt von jeder Spalte, wobei jede Spalte einen Namen und einen Datentyp hat. Die von uns oben verwendeten Objekte sind

  • Table - stellt eine Datenbanktabelle dar und ordnet sich selbst einer MetaData-Sammlung zu.

  • Column - stellt eine Spalte in einer Datenbanktabelle dar und ordnet sich selbst einem Table-Objekt zu. Die Column enthält normalerweise einen String-Namen und ein Typobjekt. Die Sammlung von Column-Objekten in Bezug auf die übergeordnete Table ist typischerweise über ein assoziatives Array unter Table.c zugänglich.

    >>> user_table.c.name
    Column('name', String(length=30), table=<user_account>)
    
    >>> user_table.c.keys()
    ['id', 'name', 'fullname']
  • Integer, String - diese Klassen stellen SQL-Datentypen dar und können an eine Column übergeben werden, entweder instanziiert oder nicht. Oben möchten wir der Spalte „name“ eine Länge von „30“ geben, daher haben wir String(30) instanziiert. Für „id“ und „fullname“ haben wir diese jedoch nicht angegeben, sodass wir die Klasse selbst übergeben können.

Siehe auch

Die Referenz- und API-Dokumentation für MetaData, Table und Column finden Sie unter Datenbanken mit MetaData beschreiben. Die Referenzdokumentation für Datentypen finden Sie unter SQL-Datentypobjekte.

In einem kommenden Abschnitt werden wir eine der grundlegenden Funktionen von Table veranschaulichen, nämlich die Erzeugung von DDL für eine bestimmte Datenbankverbindung. Aber zuerst werden wir eine zweite Table deklarieren.

Einfache Constraints deklarieren¶

Die erste Column im Beispiel user_table enthält den Parameter Column.primary_key, der eine Kurzform darstellt, um anzuzeigen, dass diese Column Teil des Primärschlüssels für diese Tabelle sein soll. Der Primärschlüssel selbst wird normalerweise implizit deklariert und durch die PrimaryKeyConstraint-Konstruktion dargestellt, die wir im Attribut Table.primary_key des Table-Objekts sehen können.

>>> user_table.primary_key
PrimaryKeyConstraint(Column('id', Integer(), table=<user_account>, primary_key=True, nullable=False))

Das Constraint, das am häufigsten explizit deklariert wird, ist das Objekt ForeignKeyConstraint, das einem Fremdschlüssel-Constraint in der Datenbank entspricht. Wenn wir Tabellen deklarieren, die miteinander verknüpft sind, verwendet SQLAlchemy die Anwesenheit dieser Fremdschlüssel-Constraint-Deklarationen nicht nur, damit sie in CREATE-Anweisungen an die Datenbank gesendet werden, sondern auch, um die Konstruktion von SQL-Ausdrücken zu unterstützen.

Ein ForeignKeyConstraint, der nur eine einzige Spalte in der Ziel-Tabelle betrifft, wird typischerweise über eine Kurzschreibweise auf Spaltenebene mithilfe des Objekts ForeignKey deklariert. Unten deklarieren wir eine zweite Tabelle address, die einen Fremdschlüssel-Constraint haben wird, der auf die user-Tabelle verweist.

>>> from sqlalchemy import ForeignKey
>>> address_table = Table(
...     "address",
...     metadata_obj,
...     Column("id", Integer, primary_key=True),
...     Column("user_id", ForeignKey("user_account.id"), nullable=False),
...     Column("email_address", String, nullable=False),
... )

Die obige Tabelle weist auch eine dritte Art von Constraint auf, die in SQL der „NOT NULL“-Constraint ist, der oben über den Parameter Column.nullable angegeben wird.

Tipp

Bei der Verwendung des Objekts ForeignKey innerhalb einer Column-Definition können wir den Datentyp für diese Column weglassen; er wird automatisch vom Datentyp der zugehörigen Spalte abgeleitet, im obigen Beispiel vom Integer-Datentyp der user_account.id-Spalte.

Im nächsten Abschnitt werden wir die abgeschlossene DDL für die Tabellen user und address senden, um das Endergebnis zu sehen.

DDL an die Datenbank senden¶

Wir haben eine Objektstruktur konstruiert, die zwei Datenbanktabellen in einer Datenbank darstellt, beginnend mit dem Root MetaData-Objekt, dann in zwei Table-Objekten, die jeweils eine Sammlung von Column- und Constraint-Objekten enthalten. Diese Objektstruktur wird das Zentrum der meisten Operationen sein, die wir mit Core und ORM weiterhin durchführen.

Die erste nützliche Sache, die wir mit dieser Struktur tun können, ist das Senden von CREATE TABLE-Anweisungen oder DDL an unsere SQLite-Datenbank, damit wir Daten daraus einfügen und abfragen können. Wir haben bereits alle Werkzeuge dazu, indem wir die Methode MetaData.create_all() auf unserem MetaData aufrufen und ihr die Engine übergeben, die auf die Ziel-Datenbank verweist.

>>> metadata_obj.create_all(engine)
BEGIN (implicit) PRAGMA main.table_...info("user_account") ... PRAGMA main.table_...info("address") ... CREATE TABLE user_account ( id INTEGER NOT NULL, name VARCHAR(30), fullname VARCHAR, PRIMARY KEY (id) ) ... CREATE TABLE address ( id INTEGER NOT NULL, user_id INTEGER NOT NULL, email_address VARCHAR NOT NULL, PRIMARY KEY (id), FOREIGN KEY(user_id) REFERENCES user_account (id) ) ... COMMIT

Der obige DDL-Erstellungsprozess enthält einige SQLite-spezifische PRAGMA-Anweisungen, die auf die Existenz jeder Tabelle prüfen, bevor ein CREATE gesendet wird. Die vollständige Reihe von Schritten ist auch innerhalb eines BEGIN/COMMIT-Paares enthalten, um transaktionale DDL zu ermöglichen.

Der Erstellungsprozess kümmert sich auch um das Senden von CREATE-Anweisungen in der richtigen Reihenfolge; oben hängt das FOREIGN KEY-Constraint von der Existenz der user-Tabelle ab, daher wird die address-Tabelle als zweite erstellt. In komplizierteren Abhängigkeitsszenarien können die FOREIGN KEY-Constraints auch nachträglich mithilfe von ALTER auf Tabellen angewendet werden.

Das MetaData-Objekt verfügt auch über eine Methode MetaData.drop_all(), die DROP-Anweisungen in umgekehrter Reihenfolge sendet, als sie CREATE senden würde, um Schemaelemente zu löschen.

Migrationswerkzeuge sind normalerweise angebracht

Insgesamt ist die CREATE / DROP-Funktion von MetaData für Testsuiten, kleine und/oder neue Anwendungen sowie für Anwendungen mit kurzlebigen Datenbanken nützlich. Für die langfristige Verwaltung eines Anwendungsdatenbankschemas ist jedoch ein Schemaverwaltungswerkzeug wie Alembic, das auf SQLAlchemy aufbaut, wahrscheinlich die bessere Wahl, da es den Prozess der inkrementellen Änderung eines festen Datenbankschemas im Laufe der Zeit verwalten und orchestrieren kann, wenn sich das Design der Anwendung ändert.

Verwendung von ORM-Deklarationsformen zur Definition von Tabellenmetadaten¶

Eine weitere Möglichkeit, Tabellenobjekte zu erstellen?

Die vorherigen Beispiele veranschaulichten die direkte Verwendung des Table-Objekts, das der Grundlage dafür dient, wie SQLAlchemy Datenbanktabellen letztendlich zur Konstruktion von SQL-Ausdrücken referenziert. Wie bereits erwähnt, bietet die SQLAlchemy ORM eine Fassade um den Prozess der Table-Deklaration, der als Deklarative Tabelle bezeichnet wird. Der Deklarative-Tabellenprozess erreicht dasselbe Ziel wie im vorherigen Abschnitt, nämlich den Aufbau von Table-Objekten, bietet uns aber im Rahmen dieses Prozesses auch etwas anderes, das als ORM-gefllagte Klasse oder einfach „gefllagte Klasse“ bezeichnet wird. Die gefllagte Klasse ist die gebräuchlichste Basiseinheit von SQL bei der Verwendung des ORM und kann im modernen SQLAlchemy auch sehr effektiv für Core-zentrierte Zwecke verwendet werden.

Einige Vorteile der Verwendung von Deklarativen Tabellen sind:

  • Ein prägnanterer und Python-typischerer Stil für die Einrichtung von Spaltendefinitionen, bei dem Python-Typen zur Darstellung von SQL-Typen verwendet werden können, die in der Datenbank verwendet werden.

  • Die resultierende gefllagte Klasse kann verwendet werden, um SQL-Ausdrücke zu bilden, die in vielen Fällen PEP 484-Typinformationen beibehalten, die von statischen Analysewerkzeugen wie Mypy und IDE-Typprüfern erfasst werden.

  • Ermöglicht die gleichzeitige Deklaration von Tabellenmetadaten und der gefllagten ORM-Klasse, die für Persistenz- / Objektladungsoperationen verwendet wird.

Dieser Abschnitt wird veranschaulichen, wie die Tabellenmetadaten der vorherigen Abschnitte mit der Deklarativen Tabelle konstruiert werden.

Bei der Verwendung des ORM wird der Prozess, mit dem wir Table-Metadaten deklarieren, normalerweise mit dem Prozess der Deklaration von gefllagten Klassen kombiniert. Die gefllagte Klasse ist jede Python-Klasse, die wir erstellen möchten, die dann Attribute hat, die mit den Spalten in einer Datenbanktabelle verknüpft werden. Obwohl es einige Variationen gibt, wie dies erreicht wird, ist der gebräuchlichste Stil als deklarativ bekannt und ermöglicht es uns, unsere benutzerdefinierten Klassen und Table-Metadaten gleichzeitig zu deklarieren.

Einrichtung einer deklarativen Basis¶

Bei Verwendung des ORM bleibt die MetaData-Sammlung bestehen, sie ist jedoch selbst mit einer ausschließlich für ORM gedachten Konstruktion verbunden, die allgemein als Deklarative Basis bezeichnet wird. Der schnellste Weg, eine neue Deklarative Basis zu erhalten, ist die Erstellung einer neuen Klasse, die von der SQLAlchemy-Klasse DeclarativeBase erbt.

>>> from sqlalchemy.orm import DeclarativeBase
>>> class Base(DeclarativeBase):
...     pass

Die obige Base-Klasse ist das, was wir die Deklarative Basis nennen werden. Wenn wir neue Klassen erstellen, die von Base erben, werden sie zusammen mit entsprechenden Klassen-Direktiven bei der Klassenerstellung jeweils als neue ORM-gefllagte Klasse etabliert, die typischerweise (aber nicht ausschließlich) auf ein bestimmtes Table-Objekt verweist.

Die Deklarative Basis verweist auf eine MetaData-Sammlung, die automatisch für uns erstellt wird, sofern wir keine von außen übergeben haben. Auf diese MetaData-Sammlung kann über das Klassenattribut DeclarativeBase.metadata zugegriffen werden. Wenn wir neue gefllagte Klassen erstellen, werden diese jeweils auf eine Table innerhalb dieser MetaData-Sammlung verweisen.

>>> Base.metadata
MetaData()

Die Deklarative Basis verweist auch auf eine Sammlung namens registry, die die zentrale „Mapper-Konfigurations“-Einheit in der SQLAlchemy ORM ist. Obwohl sie selten direkt aufgerufen wird, ist dieses Objekt zentral für den Mapper-Konfigurationsprozess, da eine Reihe von ORM-gefllagten Klassen über diese Registry miteinander koordinieren. Wie bei MetaData hat unsere Deklarative Basis auch eine registry für uns erstellt (wieder mit der Option, unsere eigene registry zu übergeben), auf die wir über die Klassenvariable DeclarativeBase.registry zugreifen können.

>>> Base.registry
<sqlalchemy.orm.decl_api.registry object at 0x...>

Andere Möglichkeiten der Zuordnung mit der registry

DeclarativeBase ist nicht die einzige Möglichkeit, Klassen zuzuordnen, nur die gebräuchlichste. registry bietet auch andere Mapper-Konfigurationsmuster, einschließlich Decorator-orientierter und imperativer Wege zur Zuordnung von Klassen. Es gibt auch volle Unterstützung für die Erstellung von Python-Dataklassen während der Zuordnung. Die Referenzdokumentation unter ORM Mapped Class Konfiguration enthält alles.

Geflaggte Klassen deklarieren¶

Mit der etablierten Base-Klasse können wir nun ORM-gefllagte Klassen für die Tabellen user_account und address in Form von neuen Klassen User und Address definieren. Wir veranschaulichen unten die modernste Form der Deklaration, die von PEP 484-Typannotationen mithilfe eines speziellen Typs Mapped angetrieben wird, der Attribute angibt, die als bestimmte Typen zugeordnet werden sollen.

>>> from typing import List
>>> from typing import Optional
>>> from sqlalchemy.orm import Mapped
>>> from sqlalchemy.orm import mapped_column
>>> from sqlalchemy.orm import relationship

>>> class User(Base):
...     __tablename__ = "user_account"
...
...     id: Mapped[int] = mapped_column(primary_key=True)
...     name: Mapped[str] = mapped_column(String(30))
...     fullname: Mapped[Optional[str]]
...
...     addresses: Mapped[List["Address"]] = relationship(back_populates="user")
...
...     def __repr__(self) -> str:
...         return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})"

>>> class Address(Base):
...     __tablename__ = "address"
...
...     id: Mapped[int] = mapped_column(primary_key=True)
...     email_address: Mapped[str]
...     user_id = mapped_column(ForeignKey("user_account.id"))
...
...     user: Mapped[User] = relationship(back_populates="addresses")
...
...     def __repr__(self) -> str:
...         return f"Address(id={self.id!r}, email_address={self.email_address!r})"

Die beiden obigen Klassen, User und Address, werden nun als ORM-gefllagte Klassen bezeichnet und sind für die Verwendung in ORM-Persistenz- und Abfrageoperationen verfügbar, die später beschrieben werden. Details zu diesen Klassen umfassen:

  • Jede Klasse verweist auf ein Table-Objekt, das als Teil des deklarativen Zuordnungsprozesses generiert wurde und durch die Zuweisung eines Strings zum Attribut DeclarativeBase.__tablename__ benannt wird. Sobald die Klasse erstellt ist, ist diese generierte Table über das Klassenattribut DeclarativeBase.__table__ verfügbar.

  • Wie bereits erwähnt, wird diese Form als Deklarative Tabellenkonfiguration bezeichnet. Ein von mehreren alternativen Deklarationsstilen würde uns stattdessen dazu veranlassen, das Table-Objekt direkt zu erstellen und es direkt DeclarativeBase.__table__ zuzuweisen. Dieser Stil wird als Deklarativ mit imperativer Tabelle bezeichnet.

  • Um Spalten in der Table anzugeben, verwenden wir die mapped_column() Konstruktion, in Kombination mit Typ-Annotationen, die auf dem Mapped Typ basieren. Dieses Objekt generiert Column Objekte, die für die Konstruktion der Table verwendet werden.

  • Für Spalten mit einfachen Datentypen und ohne weitere Optionen können wir eine Mapped Typ-Annotation allein angeben, wobei einfache Python-Typen wie int und str für Integer und String stehen. Die Anpassung, wie Python-Typen im Deklarativen Mapping-Prozess interpretiert werden, ist sehr offen gestaltet; siehe die Abschnitte Verwendung von annotierten deklarativen Tabellen (Typ-annotierte Formen für mapped_column()) und Anpassung der Typzuordnung für Hintergrundinformationen.

  • Eine Spalte kann als „nullable“ (null-fähig) oder „not null“ (nicht null-fähig) deklariert werden, basierend auf der Anwesenheit der Optional[<typ>] Typ-Annotation (oder ihren Entsprechungen, <typ> | None oder Union[<typ>, None]). Der mapped_column.nullable Parameter kann ebenfalls explizit verwendet werden (und muss nicht mit der Optionalität der Annotation übereinstimmen).

  • Die Verwendung expliziter Typ-Annotationen ist vollständig optional. Wir können mapped_column() auch ohne Annotationen verwenden. In diesem Fall würden wir explizitere Typ-Objekte wie Integer und String sowie nullable=False nach Bedarf innerhalb jeder mapped_column() Konstruktion verwenden.

  • Zwei zusätzliche Attribute, User.addresses und Address.user, definieren eine andere Art von Attribut, das als relationship() bezeichnet wird. Dieses weist ähnliche, auf Annotationen reagierende Konfigurationsstile auf, wie oben gezeigt. Die relationship() Konstruktion wird ausführlicher unter Arbeiten mit ORM-bezogenen Objekten besprochen.

  • Die Klassen erhalten automatisch eine __init__() Methode, wenn wir keine eigene deklarieren. Die Standardform dieser Methode akzeptiert alle Attributnamen als optionale Schlüsselwortargumente.

    >>> sandy = User(name="sandy", fullname="Sandy Cheeks")

    Um automatisch eine voll funktionsfähige __init__() Methode zu generieren, die Positionsargumente sowie Argumente mit Standard-Schlüsselwortwerten bereitstellt, kann die Dataclasses-Funktion verwendet werden, die unter Deklaratives Dataclass-Mapping eingeführt wurde. Es ist natürlich immer auch eine Option, eine explizite __init__() Methode zu verwenden.

  • Die __repr__() Methoden werden hinzugefügt, um eine lesbare String-Ausgabe zu erhalten; es besteht keine Anforderung, dass diese Methoden hier vorhanden sein müssen. Wie bei __init__() kann auch eine __repr__() Methode automatisch generiert werden, indem die Dataclasses-Funktion verwendet wird.

Wo ist das alte Deklarative geblieben?

Benutzer von SQLAlchemy 1.4 oder früher werden feststellen, dass das obige Mapping eine drastisch andere Form als zuvor verwendet; es verwendet nicht nur mapped_column() anstelle von Column im Deklarativen Mapping, sondern verwendet auch Python-Typ-Annotationen zur Ableitung von Spalteninformationen.

Um Kontext für Benutzer des „alten“ Weges zu schaffen, können Deklarative Mappings weiterhin unter Verwendung von Column-Objekten (sowie unter Verwendung der declarative_base() Funktion zur Erstellung der Basisklasse) wie zuvor erstellt werden, und diese Formen werden weiterhin unterstützt, ohne dass Pläne zur Abschaffung der Unterstützung bestehen. Der Grund, warum diese beiden Einrichtungen durch neue Konstrukte ersetzt werden, ist in erster Linie die nahtlose Integration mit PEP 484-Werkzeugen, einschließlich IDEs wie VSCode und Typ-Prüfern wie Mypy und Pyright, ohne dass Plugins erforderlich sind. Zweitens ist die Ableitung der Deklarationen aus Typ-Annotationen Teil von SQLAlchemys Integration mit Python-Dataclasses, die nun nativ generiert werden können.

Für Benutzer, die den „alten“ Weg mögen, aber dennoch möchten, dass ihre IDEs keine Tippfehler in ihren deklarativen Mappings melden, ist die mapped_column() Konstruktion ein Drop-in-Ersatz für Column in einem ORM-Deklarativen Mapping (beachten Sie, dass mapped_column() nur für ORM-Deklarative Mappings gilt; es kann nicht innerhalb einer Table Konstruktion verwendet werden), und die Typ-Annotationen sind optional. Unser obiges Mapping kann ohne Annotationen wie folgt geschrieben werden:

class User(Base):
    __tablename__ = "user_account"

    id = mapped_column(Integer, primary_key=True)
    name = mapped_column(String(30), nullable=False)
    fullname = mapped_column(String)

    addresses = relationship("Address", back_populates="user")

    # ... definition continues

Die obige Klasse hat einen Vorteil gegenüber einer, die Column direkt verwendet, da die Klasse User sowie Instanzen von User die korrekten Typinformationen für Typ-Werkzeuge angeben, ohne die Verwendung von Plugins. mapped_column() ermöglicht auch zusätzliche ORM-spezifische Parameter zur Konfiguration von Verhaltensweisen wie verzögerter Spaltenladung, was zuvor die Verwendung einer separaten deferred() Funktion in Verbindung mit Column erforderte.

Es gibt auch ein Beispiel für die Konvertierung einer alten Deklarationsklasse in den neuen Stil, das unter ORM-Deklarationsmodelle im Leitfaden Neues in SQLAlchemy 2.0? zu finden ist.

Siehe auch

ORM-Mapping-Stile - vollständiger Hintergrund zu verschiedenen ORM-Konfigurationsstilen.

Deklaratives Mapping - Überblick über das Deklarative Klassen-Mapping

Deklarative Tabelle mit mapped_column() - Details zur Verwendung von mapped_column() und Mapped zur Definition der Spalten innerhalb einer Table, die bei der Verwendung von Deklarativ gemappt werden soll.

Generieren von DDL für die Datenbank aus einem ORM-Mapping¶

Da unsere ORM-gemappten Klassen auf Table-Objekte innerhalb einer MetaData-Sammlung verweisen, erfolgt die Generierung von DDL für die Deklarative Basis auf die gleiche Weise wie zuvor unter Generieren von DDL für die Datenbank beschrieben. In unserem Fall haben wir die Tabellen user und address bereits in unserer SQLite-Datenbank erstellt. Hätten wir dies noch nicht getan, könnten wir die MetaData, die mit unserer ORM-Deklarativen Basisklasse verknüpft ist, verwenden, um dies zu tun. Dazu greifen wir über das Attribut DeclarativeBase.metadata auf die Sammlung zu und verwenden dann MetaData.create_all() wie zuvor. In diesem Fall werden PRAGMA-Anweisungen ausgeführt, aber keine neuen Tabellen generiert, da sie bereits vorhanden sind.

>>> Base.metadata.create_all(engine)
BEGIN (implicit) PRAGMA main.table_...info("user_account") ... PRAGMA main.table_...info("address") ... COMMIT

Tabellen-Reflexion¶

Optionaler Abschnitt

Dieser Abschnitt ist nur eine kurze Einführung in das verwandte Thema der Tabellen-Reflexion, also wie Table-Objekte automatisch aus einer bestehenden Datenbank generiert werden können. Tutorial-Leser, die mit dem Schreiben von Abfragen fortfahren möchten, können diesen Abschnitt gerne überspringen.

Um den Abschnitt über die Arbeit mit Tabellenmetadaten abzuschließen, werden wir eine weitere Operation veranschaulichen, die am Anfang des Abschnitts erwähnt wurde: die Tabellen-Reflexion. Tabellen-Reflexion bezeichnet den Prozess der Generierung von Table und verwandten Objekten durch Lesen des aktuellen Zustands einer Datenbank. Während wir in den vorherigen Abschnitten Table-Objekte in Python deklariert haben, mit der Option, DDL an die Datenbank zu senden, um ein solches Schema zu generieren, führt der Reflexionsprozess diese beiden Schritte umgekehrt aus, beginnend mit einer bestehenden Datenbank und generiert In-Python-Datenstrukturen, um die Schemata innerhalb dieser Datenbank darzustellen.

Tipp

Es gibt keine Anforderung, dass Reflexion verwendet werden muss, um SQLAlchemy mit einer bereits bestehenden Datenbank zu verwenden. Es ist durchaus üblich, dass die SQLAlchemy-Anwendung alle Metadaten explizit in Python deklariert, sodass ihre Struktur der der bestehenden Datenbank entspricht. Die Metadatenstruktur muss auch keine Tabellen, Spalten oder andere Einschränkungen und Konstrukte in der bestehenden Datenbank enthalten, die für die lokale Anwendung nicht benötigt werden.

Als Beispiel für Reflexion erstellen wir ein neues Table-Objekt, das das some_table-Objekt repräsentiert, das wir in früheren Abschnitten dieses Dokuments manuell erstellt haben. Es gibt wieder einige Varianten, wie dies durchgeführt wird, jedoch ist die grundlegendste die Konstruktion eines Table-Objekts, gegeben den Namen der Tabelle und eine MetaData-Sammlung, zu der es gehören wird, und dann anstatt einzelne Column- und Constraint-Objekte anzugeben, den Ziel-Engine über den Table.autoload_with Parameter zu übergeben.

>>> some_table = Table("some_table", metadata_obj, autoload_with=engine)
BEGIN (implicit) PRAGMA main.table_...info("some_table") [raw sql] () SELECT sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE name = ? AND type in ('table', 'view') [raw sql] ('some_table',) PRAGMA main.foreign_key_list("some_table") ... PRAGMA main.index_list("some_table") ... ROLLBACK

Am Ende des Prozesses enthält das some_table-Objekt nun die Informationen über die Column-Objekte in der Tabelle, und das Objekt ist auf genau die gleiche Weise verwendbar wie eine Table, die wir explizit deklariert haben.

>>> some_table
Table('some_table', MetaData(),
    Column('x', INTEGER(), table=<some_table>),
    Column('y', INTEGER(), table=<some_table>),
    schema=None)

Siehe auch

Lesen Sie mehr über Tabellen- und Schema-Reflexion unter Reflexion von Datenbankobjekten.

Für ORM-bezogene Varianten der Tabellen-Reflexion enthält der Abschnitt Deklaratives Mapping mit reflektierten Tabellen einen Überblick über die verfügbaren Optionen.

Nächste Schritte¶

Wir haben nun eine SQLite-Datenbank mit zwei vorhandenen Tabellen und Core- und ORM-Tabellen-orientierten Konstrukten, die wir verwenden können, um über eine Connection und/oder eine ORM Session mit diesen Tabellen zu interagieren. In den folgenden Abschnitten werden wir veranschaulichen, wie Daten mit diesen Strukturen erstellt, bearbeitet und ausgewählt werden.

SQLAlchemy 1.4 / 2.0 Tutorial

Nächster Tutorial-Abschnitt: Arbeiten mit Daten

Vorheriger: Arbeiten mit Transaktionen und DBAPI Nächster: Arbeiten mit Daten
© Copyright 2007-2025, die SQLAlchemy-Autoren und Mitwirkenden.

Die Designs von flambé! dem Drachen und Der Alchemist wurden von Rotem Yaari erstellt und großzügig gespendet.

Erstellt mit Sphinx 7.2.6. Dokumentation zuletzt generiert: Di 11 Mär 2025 14:40:17 EDT
Python

Website-Inhalt Copyright © von SQLAlchemy-Autoren und Mitwirkenden. SQLAlchemy und seine Dokumentation sind unter der MIT-Lizenz lizenziert.

SQLAlchemy ist eine Marke von Michael Bayer. mike(&)zzzcomputing.com Alle Rechte vorbehalten.

Website-Generierung durch zeekofile, mit großem Dank an das Blogofile-Projekt.

Mastodon Mastodon