Zurück zum Katalog
Season 37 7 Episoden 27 min 2026

SQLAlchemy

v2.0 — 2026 Edition. Ein umfassender Audiokurs zu SQLAlchemy, der sowohl den Core als auch das ORM abdeckt, konzipiert für die im Jahr 2026 veröffentlichte Version 2.0. Lerne, wie du deine Domain mappst, deine Anwendung strukturierst, Transaktionen mit der Session verwaltest und Queries effektiv ausführst.

Datenbanken ORM Python Core
SQLAlchemy
Aktuelle Wiedergabe
Click play to start
0:00
0:00
1
Das Fundament: Was ist SQLAlchemy und das ORM?
Willkommen bei SQLAlchemy. Wir stellen die grundlegende Architektur vor und erklären den Unterschied zwischen dem Schema-zentrierten Core und dem Domain-zentrierten ORM. Du lernst das grundlegende Vokabular und erfährst, warum du ein ORM brauchst.
4m 13s
2
Die Engine: Dein Tor zur Datenbank
Jede SQLAlchemy-Anwendung beginnt mit der Engine. Lerne, wie man eine Verbindung herstellt, was Connection Pooling ist und wie Dialekte und DBAPIs die Brücke zu deiner Datenbank schlagen.
3m 48s
3
Die Domain mappen: Declarative Base und Models
Übersetze deine Python-Klassen automatisch in Datenbanktabellen. Wir behandeln die DeclarativeBase, Mapped-Typen und wie mapped_column deine Datenbank-Metadaten aufbaut.
3m 54s
4
Projekt-Layout: Die Strukturierung deiner Anwendung
Code-Organisation ist wichtig. Lerne die Best Practices zur Strukturierung eines SQLAlchemy-Projekt-Repositories, damit deine Engine, Models und Sessions sauber und wartbar bleiben.
3m 53s
5
Die Session: Das Unit of Work meistern
Entdecke das Unit of Work-Pattern durch die ORM Session. Lerne, wie man Objekte hinzufügt, wann Flushes auftreten und wie man Transaktionen perfekt committet.
3m 52s
6
Daten abfragen: Das moderne Select-Konstrukt
Rufe deine Daten genau so ab, wie du sie brauchst. Wir erkunden das vereinheitlichte select()-Konstrukt von SQLAlchemy 2.0, das Filtern mit where() und das Ausführen von Queries mit der Session.
3m 45s
7
Die Punkte verbinden: Relationships und JOINs
Verknüpfe deine Tabellen nahtlos. Lerne, wie du Relationships konfigurierst, back_populates verwendest und SQL JOINs über verwandte Models hinweg automatisch verwaltest.
4m 04s

Episoden

1

Das Fundament: Was ist SQLAlchemy und das ORM?

4m 13s

Willkommen bei SQLAlchemy. Wir stellen die grundlegende Architektur vor und erklären den Unterschied zwischen dem Schema-zentrierten Core und dem Domain-zentrierten ORM. Du lernst das grundlegende Vokabular und erfährst, warum du ein ORM brauchst.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. SQLAlchemy, Folge 1 von 7. Hast du schon mal versehentlich eine Tabelle gelöscht oder eine Query durch einen Tippfehler in einem Raw SQL String zerschossen? Mit String Concatenation zusammengebaute Queries sind fehleranfällig, schwer zu warten und ein Sicherheitsrisiko. Diese Folge behandelt die Lösung: Die Grundlagen: Was ist SQLAlchemy und das ORM? Das zentrale Problem für Entwickler von datenbankbasierten Anwendungen ist, dass Python und relationale Datenbanken unterschiedlich ticken. Python verwendet Objekte. Objekte haben State, Verhalten und komplexe Beziehungen. Relationale Datenbanken verwenden Tabellen, Columns und Rows. Sie basieren auf Primary und Foreign Keys. Um ein Python-Objekt in eine Datenbanktabelle zu bekommen, muss sein State in ein SQL Statement übersetzt werden. Um es wieder zurückzubekommen, müssen Rows geparst und ein neues Objekt befüllt werden. Diese Reibung nennt man den Object-Relational Impedance Mismatch. Raw SQL Strings zu schreiben, um diese Übersetzung zu handhaben, ist mühsam und fehleranfällig. SQLAlchemy ist ein Python SQL Toolkit, das genau dieses Problem löst. Im Gegensatz zu manchen Tools, die versuchen, die Datenbank hinter einer Wand aus Abstraktion zu verstecken, setzt SQLAlchemy voll auf SQL. Es bietet einen robusten, pythonischen Workflow, der optimales SQL generiert und dir gleichzeitig die volle Kontrolle lässt. Die Architektur ist in zwei klare Teile aufgeteilt: den Core und das ORM. Der SQLAlchemy Core ist das Fundament. Er ist Command-orientiert und Schema-orientiert. Das bedeutet, du arbeitest direkt mit Datenbanktabellen, Columns und Rows, aber du machst das mit Python-Objekten anstatt mit Raw Text Strings. Wenn du Daten selecten willst, rufst du eine Select-Methode auf. Wenn du filtern willst, chainst du eine Where-Methode. Das beseitigt das Risiko von Syntaxfehlern durch String Concatenation und schützt vor SQL Injection. Der Core ist im Wesentlichen eine SQL Expression Language. Das ORM, also der Object Relational Mapper, setzt auf dem Core auf. Während der Core Schema-orientiert ist, ist das ORM State- und Domain-orientiert. Hier ist die entscheidende Erkenntnis: Mit dem ORM hörst du auf, in Tabellen und Rows zu denken, und fängst an, in deinem Application Domain Model zu denken. Du definierst eine Standard-Python-Klasse, zum Beispiel eine User-Klasse. Du konfigurierst das ORM so, dass es diese Klasse auf eine User-Tabelle in der Datenbank mappt, und die Class Attributes auf die Table Columns mappt. Wenn du die Datenbank mit dem ORM abfragst, bekommst du keine Raw Rows an Daten zurück. Du bekommst vollständig befüllte Instanzen deiner User-Klasse zurück. Das ORM übernimmt die Übersetzung nahtlos. Noch wichtiger ist, dass es den State dieser Objekte trackt. Wenn du einen Usernamen in Python änderst, merkt das ORM, dass das Objekt modifiziert wurde. Wenn du der Database Session sagst, dass sie deine Änderungen speichern soll, findet das ORM automatisch die richtigen Update Statements heraus und führt sie über den Core aus. Du konzentrierst dich auf deine Python-Objekte, und das ORM übernimmt die Datenbank-Synchronisation. Das Wichtigste, was du dir merken solltest, ist, dass das ORM keine Black Box ist, die den Core ersetzt. Es ist ein optionaler Layer, der komplett aus Core-Komponenten gebaut ist und es dir erlaubt, nahtlos auf explizite SQL-Generierung zurückzugreifen, wann immer deine Domain Logic maximale Performance erfordert. Wenn du diese Folgen hilfreich findest und die Show unterstützen möchtest, kannst du auf Patreon nach DevStoriesEU suchen. Danke, dass du ein paar Minuten mit mir verbracht hast. Bis zum nächsten Mal, mach's gut.
2

Die Engine: Dein Tor zur Datenbank

3m 48s

Jede SQLAlchemy-Anwendung beginnt mit der Engine. Lerne, wie man eine Verbindung herstellt, was Connection Pooling ist und wie Dialekte und DBAPIs die Brücke zu deiner Datenbank schlagen.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. SQLAlchemy, Folge 2 von 7. Du willst mit einer Datenbank kommunizieren, aber verschiedene Datenbanken sprechen unterschiedliche Dialekte, und Python Drivers haben alle ihre eigenen Macken. Du brauchst eine einzige, einheitliche Komponente, die Connection Pooling, Dialect Translation und Driver Management übernimmt, ohne dass diese Details in deine Application Logic durchsickern. Diese Komponente ist die Engine. Die Engine ist der Startpunkt für jede SQLAlchemy-Anwendung. Sie fungiert als zentrale Registry und Factory für Datenbankverbindungen. Wenn deine Anwendung mit der Datenbank kommunizieren muss, läuft das letztendlich über die Engine. Im Hintergrund verwaltet die Engine einen Connection Pool. Das bedeutet, sie hält einen Cache aktiver Datenbankverbindungen bereit und hält sie offen und einsatzbereit. Verbindungen aus einem Pool wiederzuverwenden, ist viel schneller, als jedes Mal eine brandneue Netzwerkverbindung auszuhandeln, wenn du eine Query ausführen musst. Um eine Engine zu instanziieren, nutzt du eine Funktion namens create engine. Diese Funktion braucht eine Datenbank-URL. Die URL ist ein String, der den Speicherort der Datenbank, die Credentials und zwei wichtige Konfigurationselemente liefert: den Dialekt und die DBAPI. Der Dialekt ist die Datenbankfamilie, die du ansteuerst. SQL ist ein Standard, aber jede Database Engine implementiert ihn ein bisschen anders. Der Dialekt sagt SQLAlchemy, ob es Queries für PostgreSQL, MySQL, Oracle oder SQLite formatiert. Er kümmert sich um all die herstellerspezifischen Unterschiede, damit dein Python-Code konsistent bleiben kann. Hier ist der entscheidende Punkt. SQLAlchemy verbindet sich nicht direkt mit deiner Datenbank. Es delegiert die eigentliche Netzwerkkommunikation immer an einen Third-Party Python Driver. Dieser Driver ist als DBAPI bekannt. Wenn du PostgreSQL nutzt, ist deine DBAPI vielleicht psycopg2. Wenn du SQLite nutzt, ist es typischerweise pysqlite. Die Datenbank-URL gibt beides zusammen an. Zum Beispiel könnte die URL mit dem String sqlite plus pysqlite beginnen. Das sagt der Engine explizit, dass sie Queries mit dem SQLite-Dialekt formatieren und mit dem pysqlite Driver übertragen soll. Schauen wir uns an, wie man eine In-Memory SQLite-Datenbank aufsetzt. Das ist ein sehr gängiges Pattern fürs Testing, weil die Datenbank komplett im RAM lebt und verschwindet, wenn das Programm beendet wird. Du rufst die create engine Funktion auf und übergibst ihr deinen URL-String. Für eine In-Memory-Datenbank ist die URL sqlite plus pysqlite Doppelpunkt Schrägstrich Schrägstrich Schrägstrich Doppelpunkt memory Doppelpunkt. Wenn du diese Zeile Code ausführst, wird das Engine-Objekt erstellt, aber es verbindet sich nicht sofort mit der Datenbank. Die Engine ist lazy. Sie bereitet die Konfiguration vor und setzt den Connection Pool auf, aber sie wartet bis zum allerersten Mal, dass du sie explizit bittest, einen Task auszuführen, bevor sie tatsächlich die DBAPI kontaktiert, um eine Verbindung herzustellen. Während der Entwicklung musst du oft genau überprüfen, was SQLAlchemy an die Datenbank sendet. Die create engine Funktion akzeptiert einen optionalen Parameter namens echo. Wenn du echo auf true setzt, loggt die Engine alle rohen SQL-Statements, die sie generiert, direkt in deinen Standard Output. Sie fungiert als eingebautes Debugging-Tool und lässt dich die genaue Übersetzung zwischen deinen Python-Operationen und dem resultierenden SQL sehen. Die Engine existiert, um die unordentliche Realität von Netzwerkverbindungen und Database Drivers zu abstrahieren. Sie gibt deiner Anwendung ein sauberes, stabiles Interface und stellt sicher, dass sich der Rest deines Codes nie darum kümmern muss, wie die Datenbank physisch erreicht wird. Danke fürs Dabeisein. Ich hoffe, du hast etwas Neues mitgenommen.
3

Die Domain mappen: Declarative Base und Models

3m 54s

Übersetze deine Python-Klassen automatisch in Datenbanktabellen. Wir behandeln die DeclarativeBase, Mapped-Typen und wie mapped_column deine Datenbank-Metadaten aufbaut.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. SQLAlchemy, Folge 3 von 7. Du schreibst deine Python Domain Models und musst danach noch jede Menge SQL schreiben, nur um die Tabellen dafür zu erstellen. Mit der Zeit driften diese beiden separaten Definitionen fast immer auseinander. Was wäre, wenn deine Python-Klassen dein Database Schema automatisch entwerfen könnten? Genau das lösen wir heute mit Mapping the Domain: Declarative Base und Models. Bevor wir uns die Klassen selbst ansehen, müssen wir über Database Metadata sprechen. In SQLAlchemy sind Metadata im Prinzip ein Strukturkatalog. Es ist eine zentrale Python Registry, die den exakten Blueprint deiner Datenbank speichert. Sie trackt jede Tabelle, jede Column und jedes Constraint, das du definierst. Wann immer du eine Klasse in SQLAlchemy mappst, fließen die Details dieser Klasse direkt in diesen einen Katalog. Um deine Python-Klassen mit diesem Metadata-Katalog zu verbinden, nutzt du ein Konstrukt namens DeclarativeBase. Du nutzt DeclarativeBase nicht direkt. Stattdessen erstellst du deine eigene Custom Base Class, indem du davon erbst. Ab diesem Zeitpunkt wird jedes einzelne Model, das du in deiner Applikation baust, von deiner Custom Base Class erben. In dem Moment, in dem eine Klasse davon erbt, registriert SQLAlchemy dieses neue Model im Hintergrund im zugrunde liegenden Metadata-Katalog. Schauen wir uns an, wie du ein User Model erstellst. Du definierst eine Python-Klasse namens User und erbst von deiner Custom Base Class. Das Erste, was du innerhalb dieser Klasse definierst, ist ein Attribut namens tablename, geschrieben mit doppelten Unterstrichen auf beiden Seiten. Das setzt du auf den String user_account. Diese explizite Zuweisung sagt SQLAlchemy genau, in welcher zugrunde liegenden Datenbanktabelle diese Python-Objekte gespeichert werden. Als Nächstes legst du die Columns fest. SQLAlchemy 2.0 verlässt sich dafür auf Standard Python Type Hints. Du definierst deine Attribute mit einer speziellen Annotation namens Mapped. Für einen Identifier annotierst du dein ID-Attribut als Mapped, das einen Integer enthält. Für einen Username annotierst du es als Mapped, das einen String enthält. Dieser Type Hint ist ausschließlich für Python gedacht. Er sagt deiner IDE und deinem Type Checker, welche Daten zu erwarten sind. Aber die Database Engine braucht spezifischere Anweisungen als einen einfachen Python-Typ. Hier kommt eine Funktion namens mapped_column ins Spiel. Du weist mapped_column deinem Klassenattribut zu, und innerhalb der Klammern konfigurierst du die datenbankspezifischen Regeln. Für deine User-ID rufst du mapped_column auf und übergibst ein Flag, das sie explizit als Primary Key markiert. Für eine String Column übergibst du vielleicht ein maximales Character Limit oder ein Flag, das vorschreibt, dass das Feld unique sein muss. Wenn dein Python Type Hint den gesamten Kontext liefert, den SQLAlchemy braucht, kannst du mapped_column tatsächlich komplett weglassen. SQLAlchemy leitet dann eine einfache Standard Database Column direkt aus der Mapped Annotation ab. Aber für Primary Keys oder spezifische Database Constraints ist mapped_column zwingend erforderlich. Hier ist der entscheidende Punkt: Sobald deine Python-Klassen geschrieben sind, ist dein Schema Design bereits abgeschlossen. Der Metadata-Katalog enthält nun eine perfekte Map deiner Domain. Du kannst eine Methode namens create_all auf den Metadata deiner Base Class aufrufen und deine Database Engine übergeben. SQLAlchemy schaut sich deine User-Klasse an, liest die Mapped Columns, übersetzt sie sofort in perfekt formatierte CREATE TABLE Statements und wendet sie an. Genau derselbe Python-Code, den du schreibst, um deine Applikation auszuführen, wird zur Single Source of Truth, die deine Datenbankstruktur baut. Danke, dass du dabei warst. Ich hoffe, du konntest etwas Neues mitnehmen.
4

Projekt-Layout: Die Strukturierung deiner Anwendung

3m 53s

Code-Organisation ist wichtig. Lerne die Best Practices zur Strukturierung eines SQLAlchemy-Projekt-Repositories, damit deine Engine, Models und Sessions sauber und wartbar bleiben.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. SQLAlchemy, Folge 4 von 7. Du hast deine Models, deine Engine und deine Queries geschrieben. Aber sie alle in eine einzige Datei zu packen, ist der direkte Weg in einen Wartungs-Albtraum und zu Circular Imports. Die Lösung ist das Project Layout: Die Strukturierung deiner Applikation. Wenn du dir Tutorials anschaust, steht der Code meistens in einem einzigen Skript. Du siehst das Engine-Setup, die Base Class, die Models und die Queries von oben nach unten aufgereiht. Dieses Design ist super, um die Syntax zu lernen, aber wenn du versuchst, so ein Production-System zu bauen, fällt es auseinander. Sobald du Web Routes oder Background Workers hinzufügst, bekommst du Probleme. Wenn eine Web Route ein User Model importieren muss, das User Model aber in derselben Datei liegt, die den Application Server startet oder die Database Connection initialisiert, kommt Python durcheinander. Du landest bei Circular Imports und dein Code wird unmöglich zu testen. Du brauchst eine strikte Separation of Concerns. Das Standard-Pattern ist, dieses einzelne Skript in verschiedene Module aufzuteilen, basierend auf ihrem Job. Zuerst erstellst du eine dedizierte Datei, typischerweise database dot py genannt. Diese Datei hat genau eine Responsibility, nämlich das Managen der Database Connection. Hier packst du deinen create engine Call rein und richtest deinen Session Maker ein. Du definierst hier keine Tabellen und du führst hier keine Queries aus. Indem du die Engine isolierst, stellst du sicher, dass deine Applikation nur einen einzigen Connection Pool erstellt. Jedes andere Modul in deinem Projekt kann den Session Maker sicher aus dieser Datei importieren, ohne versehentlich Application Startup Logic auszulösen. Als Nächstes verschiebst du deine Tabellendefinitionen in eine Datei namens models dot py. Diese Datei enthält deine Declarative Base und all deine Mapped Classes, wie ein User- oder ein Address-Objekt. Sie importiert nichts aus deiner Database-Datei. Das ist der entscheidende Punkt. Deine Models definieren die Struktur deiner Daten, aber sie wissen nicht, wie sie sich mit der Datenbank verbinden. Weil models dot py keine Dependencies zur Engine oder zur aktiven Session hat, kannst du deine Mapped Classes überall in deiner Applikation importieren, ohne dir Sorgen um Side Effects machen zu müssen. Wenn dein Projekt größer wird, teilst du die Models vielleicht sogar in ein Directory mit separaten Dateien für verschiedene Domains auf. Solange sie alle exakt dieselbe Declarative Base Instanz importieren, weiß SQLAlchemy, dass sie zur selben Metadata Collection gehören. Schließlich brauchst du einen Ort, um deine Queries tatsächlich auszuführen. Du hältst die Query Execution komplett getrennt von deinen Models und Connection-Dateien. Normalerweise kommt das in deine Route Handlers oder dedizierte Service-Dateien. Wenn eine Applikation Daten braucht, importiert die Service-Datei den Session Maker aus deinem Database-Modul und die benötigten Mapped Classes aus deinem Models-Modul. Sie öffnet eine Session über einen Context Manager, führt ein Select Statement aus, holt die Objekte und lässt den Context Manager die Connection sicher schließen, wenn der Block endet. Die Service-Datei fungiert als Coordinator. Dein Projekt so zu strukturieren, hält deine Connection Logic isoliert, deine Data Schemas portabel und deine Business Operations sauber. Die allerwichtigste Regel, die du dir merken musst, ist, dass deine Data Models niemals deine Database Engine importieren sollten. Das war's für diese Folge. Danke fürs Zuhören und keep building!
5

Die Session: Das Unit of Work meistern

3m 52s

Entdecke das Unit of Work-Pattern durch die ORM Session. Lerne, wie man Objekte hinzufügt, wann Flushes auftreten und wie man Transaktionen perfekt committet.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. SQLAlchemy, Folge 5 von 7. Stell dir eine Staging Area vor, in der du Dutzende von Datenbankänderungen in eine Queue stellen und sie alle perfekt auf einmal pushen oder sofort abbrechen kannst. Genau dieses Problem löst das Konzept in dieser Folge: Die Session: Das Unit of Work meistern. Die SQLAlchemy Session ist der primäre Weg, wie deine Python-Objekte mit der Datenbank kommunizieren. Sie arbeitet nach einem Pattern namens Unit of Work. Wenn du die Session benutzt, feuerst du nicht einzelne Befehle direkt auf die Datenbank ab. Du interagierst mit einem smarten Workspace. Die Session überwacht deine Operationen, sammelt die Hinzufügungen, Änderungen und Löschungen und berechnet den effizientesten Weg, sie zum richtigen Zeitpunkt in SQL zu übersetzen. Innerhalb dieses Workspaces gibt es einen Mechanismus namens Identity Map. Das ist ein internes Dictionary, das den Primary Key einer Datenbankzeile mit der spezifischen Speicheradresse deines Python-Objekts verknüpft. Wenn du einen User mit der ID fünf anfragst, checkt die Session zuerst die Identity Map. Wenn das Objekt schon geladen ist, bekommst du exakt dieselbe Python-Instanz zurück. Das garantiert, dass du niemals zwei unterschiedliche Python-Objekte hast, die gleichzeitig dieselbe Datenbankzeile repräsentieren. Schauen wir uns das Einfügen neuer Daten an. Du startest, indem du eine Instanz deiner gemappten User-Klasse erstellst und ihr einen Namen wie Alice gibst. In dieser Phase ist dein Objekt in einem Zustand namens transient. Es existiert ausschließlich im Python-Speicher. Die Datenbank hat keine Ahnung, dass es existiert, und auch die Session weiß nichts davon. Um das Objekt mit deinem Workspace zu verlinken, übergibst du es an die add-Methode der Session. Das Objekt wechselt in einen Zustand namens pending. Die Session hat deine Absicht, diesen neuen User einzufügen, registriert, aber sie hat noch kein SQL über das Netzwerk gesendet. Das Objekt wartet einfach in der Queue. Das bringt uns zum strikten Unterschied zwischen einem flush und einem commit. Wenn du flush auf der Session aufrufst, nimmt sie deine pending Queue und pusht die Änderungen in die aktuelle Datenbank-Transaktion. Sie sendet das SQL INSERT Statement ab. Die Datenbank führt es aus und weist einen Primary Key zu. Zurück in deinem Python-Code wird dein User-Objekt sofort mit dieser neuen Datenbank-ID befüllt. Das Objekt ist in einen persistenten Zustand übergegangen. Hier ist der entscheidende Punkt. Auch wenn das Objekt persistent ist und eine ID hat, ist die Änderung immer noch nicht permanent. Die Datenbank isoliert diese Transaktion. Angenommen, dein Code fängt plötzlich einen Fehler ab, wie eine ungültige E-Mail-Adresse für den User, den du gerade geflusht hast. Weil du noch nicht committet hast, kannst du einen rollback ausführen. Die Datenbank verwirft die Transaktion komplett, und nichts wird in den eigentlichen Tabellen gespeichert. Wenn du absolut sicher bist, dass die Daten korrekt sind, rufst du commit auf. Ein commit finalisiert die Transaktion und speichert die Daten auf der Festplatte. Der Aufruf von commit triggert automatisch zuerst einen flush, sodass du flush in der Regel nicht manuell aufrufen musst, es sei denn, du musst spezifisch einen generierten Primary Key lesen, bevor du den Rest deiner Logik abschließt. Die Session fungiert als Buffer zwischen deinem Application Memory und dem permanenten Storage und erlaubt dir, komplexe Datenänderungen sicher zu orchestrieren, bevor du sie in die Realität umsetzt. Danke fürs Zuhören. Macht's gut, Leute.
6

Daten abfragen: Das moderne Select-Konstrukt

3m 45s

Rufe deine Daten genau so ab, wie du sie brauchst. Wir erkunden das vereinheitlichte select()-Konstrukt von SQLAlchemy 2.0, das Filtern mit where() und das Ausführen von Queries mit der Session.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. SQLAlchemy, Folge 6 von 7. In älteren Versionen von SQLAlchemy fühlte sich das Schreiben von Queries an, als würdest du mit einem Split-Brain arbeiten. Du musstest dir eine Syntax für Core-Operationen und völlig andere Regeln für das ORM merken. Jedes Mal, wenn du eine Query geschrieben hast, musstest du innehalten und dich fragen, ob du Raw Rows oder gemappte Objekte fetchst. Version 2.0 hat diese Grenze mit dem modernen Select-Construct aufgehoben. Das Konzept ist simpel. Es gibt jetzt eine einzige, einheitliche Funktion namens select. Du übergibst die Entity, die du abfragen willst, direkt an sie. Wenn du eine ORM-Klasse namens User hast, übergibst du die User-Klasse an die select-Funktion. Das erstellt ein select-Objekt, das eine Query gegen die zugrundeliegende User-Tabelle repräsentiert. Dieses select-Objekt ist generativ. Der Aufruf der select-Funktion führt noch nichts auf der Datenbank aus. Stattdessen erstellt es ein Expression-Objekt im Memory. Wenn du eine Methode auf diesem Objekt aufrufst, um Conditions hinzuzufügen, gibt es ein frisches select-Objekt mit diesen neuen Conditions zurück. Dadurch kannst du komplexe Queries dynamisch und Schritt für Schritt zusammenbauen und das Objekt in deiner Application herumreichen, bevor du überhaupt mit der Datenbank sprichst. Das deckt die Base-Query ab. Wie filterst du sie? Du hängst die where-Methode an dein select-Objekt an. Innerhalb der where-Methode benutzt du Standard-Python-Operatoren direkt auf deinen gemappten Class-Attributes. Um zum Beispiel einen bestimmten User zu finden, tippst du die User-Klasse Punkt name, gefolgt von zwei Gleichheitszeichen und dem Target-String. SQLAlchemy fängt das ab. Es überlädt Standard-Python-Operatoren wie das doppelte Gleichheitszeichen oder das Größer-als-Zeichen. Anstatt die Expression in Python zu true oder false zu evaluieren, übersetzt es sie in die korrekte SQL-Syntax für die WHERE-Clause der Datenbank. Jetzt hast du ein vollständig zusammengebautes Query-Objekt. Um deine Daten tatsächlich abzurufen, übergibst du dieses Objekt an eine Session. Du kannst es an die Standard-execute-Methode der Session übergeben, aber das gibt ein Result-Objekt zurück, in dem jede Row im Wesentlichen ein Tuple ist. Selbst wenn du eine einzelne ORM-Klasse gequeryt hast, ist dein gemapptes Objekt in einem Ein-Element-Tuple gefangen, und du musst es nach dem Return manuell extrahieren. Hier ist der entscheidende Punkt. Wenn du ORM-Objekte zurückbekommen willst, nutze stattdessen die scalars-Methode auf der Session. Du übergibst dein select-Objekt an Session Punkt scalars. Die Session führt die Query aus, entpackt diese Tuples automatisch aus dem zugrundeliegenden Result-Set und liefert ein Iterable deiner vollständig befüllten ORM-Objekte. Du bekommst sofort eine saubere Collection von User-Instances, bereit zum Modifizieren oder Lesen. Das einheitliche select-Construct bedeutet, dass exakt dieselben Query-Bausteine, die du für ORM-Objekte benutzt, direkt gegen Low-Level-Core-Connections ausgeführt werden können. Dadurch musst du nur noch ein einziges mentales Modell für deinen gesamten Database-Layer pflegen. Das war's für diese Folge. Danke fürs Zuhören und keep building!
7

Die Punkte verbinden: Relationships und JOINs

4m 04s

Verknüpfe deine Tabellen nahtlos. Lerne, wie du Relationships konfigurierst, back_populates verwendest und SQL JOINs über verwandte Models hinweg automatisch verwaltest.

Herunterladen
Hallo, hier ist Alex von DEV STORIES DOT EU. SQLAlchemy, Folge 7 von 7. Relationale Datenbanken existieren, weil Daten miteinander verknüpft sind. Aber jedes Mal manuell komplexe Joins zu schreiben, wenn du einen verknüpften Datensatz brauchst, wird schnell lästig. Am Ende hast du repetitive Query-Logik, die über deine ganze Application verstreut ist. Connecting the Dots: Relationships und Joins löst dieses Problem, indem der Object-Relational Mapper die Verbindungen für dich übernimmt. Auf Datenbankebene werden Tabellen über Foreign Keys verknüpft. Wenn ein User mehrere Adressen hat, enthält die Address-Tabelle eine Column, die die User-ID speichert. Das ist eine Standard-One-to-Many-Relationship. Aber wenn du Python-Code schreibst, willst du nicht erst eine ID extrahieren und eine zweite Query schreiben, nur um diese Adressen zu finden. Du willst auf eine Property deines User-Objects zugreifen und sofort eine Liste von Address-Objects sehen. Genau das bietet das Relationship-Construct. Es schließt die Lücke zwischen Datenbank-Foreign-Keys und Python-Object-Attributes. Um das aufzusetzen, brauchst du zwei Dinge. Erstens deklarierst du den Foreign Key auf der Datenbankseite. In deinem Address-Model definierst du eine Column namens User-ID und markierst sie explizit als Foreign Key, der auf die User-Tabelle zeigt. Zweitens definierst du die Relationship auf der Python-Seite. In deinem User-Model definierst du eine Property namens addresses über die Relationship-Function, die auf das Address-Model zeigt. Außerdem definierst du eine Relationship-Property im Address-Model, die zurück zum User zeigt. Hier ist der entscheidende Punkt. SQLAlchemy muss wissen, dass diese beiden Properties die zwei Seiten von exakt derselben Verbindung darstellen. Das teilst du dem Framework mit, indem du den back populates Parameter in beiden Relationship-Definitionen verwendest. Im User-Model setzt die addresses Relationship back populates auf den String-Namen der User-Property. Im Address-Model setzt die User-Relationship back populates auf den String-Namen der addresses Property. Wegen back populates hält das ORM deine Python-Objects im Memory synchron. Wenn du ein Address-Object nimmst und es einem User zuweist, taucht diese Adresse sofort in der Address-Liste des Users auf. Das Framework übernimmt das Bookkeeping, bevor du überhaupt irgendetwas in die Datenbank committest. Sobald deine Objects verlinkt sind, fragst du sie per Query ab. Angenommen, du führst ein Select-Statement aus, um einen User namens Alice zu finden. Die Datenbank gibt die User-Row zurück, und du bekommst ein Object. Genau in diesem Moment sind Alices Adressen noch nicht geladen. Das ORM fetcht sie nicht, weil du noch nicht danach gefragt hast. Wenn du schließlich in deinem Code auf die addresses Property zugreifst, vielleicht um über die Straßennamen zu iterieren, bemerkt das ORM, dass die Daten fehlen. Es pausiert dein Programm automatisch, schickt ein zweites Select-Statement an die Datenbank, um alle Adressen mit Alices ID zu finden, und befüllt die Liste. Das nennt man Lazy Loading. Es ist das Default-Behavior, weil es verhindert, dass die Application tausende verknüpfte Rows in den Memory zieht, es sei denn, sie werden wirklich gebraucht. Du fragst einen User per Query ab, greifst auf seine Properties zu, und das System navigiert nahtlos durch die Foreign Keys und führt die nötigen Queries im Hintergrund aus. Die wahre Stärke des Relationship-Constructs ist, dass es die mechanische Komplexität von Joins versteckt und dich eine ganze Datenbank navigieren lässt, indem du einfach mit verbundenen Python-Objects interagierst. Um diese Konzepte zu meistern, schau dir die offizielle Documentation an und versuche hands-on, deine eigenen Models aufzusetzen. Besuche gerne devstories dot eu, um Themen vorzuschlagen, die du in zukünftigen Serien behandelt haben möchtest. Das war's für diese Folge. Danke fürs Zuhören und keep building!