Einführung in SQLAlchemy

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

SQLAlchemy ist eine Bibliothek, die für die Interaktion mit einer Vielzahl von Datenbanken verwendet wird. Mit ihr kannst du Datenmodelle und Abfragen so erstellen, dass sie sich wie normale Python-Klassen und -Anweisungen anfühlen. SQLAlchemy wurde 2005 von Mike Bayer entwickelt und wird von vielen großen und kleinen Unternehmen eingesetzt. Viele halten sie für die de facto Methode, um mit relationalen Datenbanken in Python zu arbeiten.

Mit kannst du dich mit den meisten gängigen Datenbanken wie Postgres, MySQL, SQLite, Oracle und vielen anderen verbinden. Es bietet auch die Möglichkeit, die Unterstützung für andere relationale Datenbanken hinzuzufügen. Amazon Redshift, das einen benutzerdefinierten Dialekt von PostgreSQL verwendet, ist ein gutes Beispiel für die Unterstützung von Datenbanken durch die Community.

In diesem Kapitel erfahren wir, warum wir SQLAlchemy brauchen, lernen seine beiden Hauptmodi kennen und stellen eine Verbindung zu einer Datenbank her.

Warum SQLAlchemy verwenden?

Der wichtigste Grund für die Verwendung von SQLAlchemy ist die Abstraktion deines Codes von der zugrunde liegenden Datenbank und den damit verbundenen SQL-Eigenheiten. SQLAlchemy nutzt leistungsstarke gemeinsame Anweisungen und Typen, um sicherzustellen, dass die SQL-Anweisungen für jeden Datenbanktyp und -anbieter effizient und korrekt erstellt werden, ohne dass du darüber nachdenken musst. Das macht es einfach, Logik von Oracle zu PostgreSQL oder von einer Anwendungsdatenbank zu einem Data Warehouse zu migrieren. Außerdem wird sichergestellt, dass die Datenbankeingabe bereinigt und mit dem richtigen Escape versehen wird, bevor sie an die Datenbank übermittelt wird. Dadurch werden häufige Probleme wie SQL-Injection-Angriffe verhindert.

SQLAlchemy bietet außerdem eine große Flexibilität, indem es zwei Hauptverwendungsmodi zur Verfügung stellt: SQL Expression Language (gemeinhin als Core bezeichnet) und ORM. Diese Modi können getrennt oder zusammen verwendet werden, je nach deinen Vorlieben und den Anforderungen deiner Anwendung.

SQLAlchemy Core und die SQL-Ausdruckssprache

Die SQL Expression Language ist eine pythonische Art, gängige SQL-Anweisungen und -Ausdrücke darzustellen, und stellt nur eine leichte Abstraktion der typischen SQL-Sprache dar. Sie konzentriert sich auf das eigentliche Datenbankschema, ist aber so standardisiert, dass sie eine einheitliche Sprache für eine große Anzahl von Backend-Datenbanken bietet. Die SQL Expression Language dient auch als Grundlage für den SQLAlchemy ORM.

ORM

Der SQLAlchemy ORM ähnelt vielen anderen objektrelationalen Mappern (ORMs), die du vielleicht schon aus anderen Sprachen kennst. Es konzentriert sich auf das Domänenmodell der Anwendung und nutzt das Unit of Work-Muster, um den Objektstatus zu verwalten. Sie bietet außerdem eine High-Level-Abstraktion über der SQL Expression Language, die es dem Benutzer ermöglicht, auf eine idiomatischere Weise zu arbeiten. Du kannst die ORM mit der SQL Expression Language kombinieren, um sehr leistungsfähige Anwendungen zu erstellen. Der ORM nutzt ein deklaratives System, das den Active-Record-Systemen ähnelt, die von vielen anderen ORMs verwendet werden, z. B. dem in Ruby on Rails.

Der ORM ist zwar sehr nützlich, aber du musst bedenken, dass es einen Unterschied zwischen der Art und Weise gibt, wie Klassen miteinander verbunden werden können, und wie die zugrunde liegenden Datenbankbeziehungen funktionieren. Wie sich das auf deine Implementierung auswirken kann, werden wir in Kapitel 6 genauer untersuchen.

Die Wahl zwischen SQLAlchemy Core und ORM

Bevor du mit der Erstellung von Anwendungen mit SQLAlchemy beginnst, musst du dich entscheiden, ob du primär den ORM oder den Core verwenden willst. Die Entscheidung, ob du SQLAlchemy Core oder ORM als dominante Datenzugriffsschicht für eine Anwendung verwendest, hängt oft von einigen Faktoren und persönlichen Vorlieben ab.

Die beiden Modi verwenden eine leicht unterschiedliche Syntax, aber der größte Unterschied zwischen Core und ORM ist die Sicht auf die Daten als Schema oder Geschäftsobjekte. SQLAlchemy Core hat eine schema-zentrierte Sichtweise, die sich wie traditionelles SQL auf Tabellen, Schlüssel und Indexstrukturen konzentriert. SQLAlchemy Core eignet sich hervorragend für Data Warehouse, Reporting, Analyse und andere Szenarien, in denen eine genaue Kontrolle der Abfrage oder die Arbeit mit nicht modellierten Daten sinnvoll ist. Der starke Datenbankverbindungspool und die Ergebnismengenoptimierung eignen sich perfekt für den Umgang mit großen Datenmengen, sogar in mehreren Datenbanken.

Wenn du jedoch vorhast, dich mehr auf ein domänenorientiertes Design zu konzentrieren, wird der ORM einen Großteil des zugrunde liegenden Schemas und der Struktur in Metadaten und Geschäftsobjekten kapseln. Diese Kapselung macht es einfach, Datenbankinteraktionen wie normalen Python-Code zu gestalten. Die meisten gängigen Anwendungen lassen sich auf diese Weise modellieren. Es kann auch ein sehr effektiver Weg sein, um einer Legacy-Anwendung oder einer Anwendung, die mit rohen SQL-Anweisungen durchsetzt ist, ein domänenorientiertes Design zu geben. Microservices profitieren auch von der Abstraktion der zugrundeliegenden Datenbank, die es dem Entwickler ermöglicht, sich nur auf den zu implementierenden Prozess zu konzentrieren.

Da der ORM jedoch auf SQLAlchemy Core aufbaut, kannst du seine Fähigkeit nutzen, mit Diensten wie Oracle Data Warehousing und Amazon Redshift auf die gleiche Weise zusammenzuarbeiten wie mit MySQL. Das macht es zu einer wunderbaren Ergänzung zum ORM, wenn du Geschäftsobjekte und Warehousedaten kombinieren musst.

Hier ist eine kurze Checkliste, die dir hilft zu entscheiden, welche Option für dich am besten ist:

  • Wenn du mit einem Framework arbeitest, in dem bereits ein ORM integriert ist, du aber ein leistungsfähigeres Reporting hinzufügen möchtest, verwende Core.

  • Wenn du deine Daten in einer eher schema-zentrierten Ansicht (wie in SQL) anzeigen möchtest, verwende Core.

  • Wenn du Daten hast, für die keine Geschäftsobjekte benötigt werden, verwende Core.

  • Wenn du deine Daten als Geschäftsobjekte betrachtest, verwende ORM.

  • Wenn du einen schnellen Prototyp baust, verwende ORM.

  • Wenn du eine Kombination von Bedürfnissen hast, die sowohl Geschäftsobjekte als auch andere Daten, die nichts mit der Problemdomäne zu tun haben, nutzen kannst, dann verwende beides!

Nachdem du nun weißt, wie SQLAlchemy aufgebaut ist und was der Unterschied zwischen Core und ORM ist, können wir SQLAlchemy installieren und mit der Verbindung zu einer Datenbank beginnen.

SQLAlchemy installieren und eine Verbindung zu einer Datenbank herstellen

SQLAlchemy kann mit Python 2.6, Python 3.3 und Pypy 2.1 oder höher verwendet werden. Ich empfehle, pip zu verwenden, um die Installation mit dem Befehl pip install durchzuführen sqlalchemy. Es ist erwähnenswert, dass es auch mit easy_install und distutils installiert werden kann; pip ist jedoch die einfachere Methode. Während der Installation versucht SQLAlchemy, einige C-Erweiterungen zu erstellen, die die Arbeit mit Ergebnismengen schneller und speichereffizienter machen. Wenn du diese Erweiterungen deaktivieren musst, weil es auf dem System, auf dem du installierst, keinen Compiler gibt, kannst du mit --global-option=--without-cextensions. Beachte, dass sich die Verwendung von SQLAlchemy ohne C-Erweiterungen negativ auf die Leistung auswirkt, und du solltest deinen Code auf einem System mit C-Erweiterungen testen, bevor du ihn optimierst.

Installation von Datenbanktreibern

Unter unterstützt SQLAlchemy standardmäßig SQLite3 ohne zusätzliche Treiber. Für die Verbindung zu anderen Datenbanken wird jedoch ein zusätzlicher Datenbanktreiber benötigt, der die Standard-Python DBAPI (PEP-249) Spezifikation verwendet. Diese DBAPIs bilden die Grundlage für den Dialekt, den jeder Datenbankserver spricht, und ermöglichen oft die einzigartigen Funktionen der verschiedenen Datenbankserver und Versionen. Obwohl es für viele Datenbanken mehrere DBAPIs gibt, konzentriert sich die folgende Anleitung auf die gängigsten:

PostgreSQL

Psycopg2 bietet breite Unterstützung für PostgreSQL Versionen und Funktionen und kann mit pip install psycopg2 installiert werden.

MySQL

PyMySQL ist meine bevorzugte Python-Bibliothek für die Verbindung zu einem MySQL-Datenbankserver. Sie kann mit pip install pymysql installiert werden. Die MySQL-Unterstützung in SQLAlchemy erfordert die MySQL-Version 4.1 und höher, weil die Passwörter vor dieser Version nicht funktionieren. Wenn ein bestimmter Statement-Typ nur in einer bestimmten Version von MySQL verfügbar ist, bietet SQLAlchemy keine Methode, um diese Statements in Versionen von MySQL zu verwenden, in denen das Statement nicht verfügbar ist. Es ist wichtig, die MySQL-Dokumentation zu lesen, wenn eine bestimmte Komponente oder Funktion in SQLAlchemy in deiner Umgebung nicht zu funktionieren scheint.

Andere

SQLAlchemy kann auch in Verbindung mit Drizzle, Firebird, Oracle, Sybase und Microsoft SQL Server verwendet werden. Die Community hat auch externe Dialekte für viele andere Datenbanken wie IBM DB2, Informix, Amazon Redshift, EXASolution, SAP SQL Anywhere, Monet und viele andere bereitgestellt. Die Erstellung eines zusätzlichen Dialekts wird von SQLAlchemy gut unterstützt, und in Kapitel 7 wird untersucht, wie man genau das macht.

Da wir nun SQLAlchemy und eine DBAPI installiert haben, können wir eine Engine bauen, die sich mit einer Datenbank verbindet.

Verbinden mit einer Datenbank

Um mit einer Datenbank zu verbinden, müssen wir eine SQLAlchemy-Engine erstellen. Die SQLAlchemy-Engine schafft eine gemeinsame Schnittstelle zur Datenbank, um SQL-Anweisungen auszuführen. Dazu wickelt sie einen Pool von Datenbankverbindungen und einen Dialekt so ein, dass sie zusammenarbeiten können, um einen einheitlichen Zugriff auf die Backend-Datenbank zu ermöglichen. So muss sich unser Python-Code nicht um die Unterschiede zwischen Datenbanken oder DBAPIs kümmern.

SQLAlchemy bietet eine Funktion, mit der wir eine Engine erstellen können, wenn wir einen Connection String und optional einige zusätzliche Schlüsselwortargumente angeben. Ein Verbindungsstring ist eine speziell formatierte Zeichenkette, die Folgendes enthält:

  • Datenbanktyp (Postgres, MySQL, etc.)

  • Dialekt, es sei denn, der Standard für den Datenbanktyp (Psycopg2, PyMySQL, etc.)

  • Optionale Authentifizierungsdaten (Benutzername und Passwort)

  • Speicherort der Datenbank (Datei oder Hostname des Datenbankservers)

  • Optionaler Datenbankserver-Port

  • Optionaler Datenbankname

Bei SQLite Datenbankverbindungsstrings müssen wir eine bestimmte Datei oder einen Speicherort angeben. Beispiel P-1 definiert eine SQLite-Datenbankdatei mit dem Namen cookies.db, die über einen relativen Pfad in der zweiten Zeile im aktuellen Verzeichnis gespeichert wird, eine In-Memory-Datenbank in der dritten Zeile und einen vollständigen Pfad zur Datei in der vierten (Unix) und fünften (Windows) Zeile. Unter Windows würde der Verbindungsstring wie engine4 aussehen; die \\ sind erforderlich, damit die Zeichenketten richtig umbrochen werden, es sei denn, du verwendest eine rohe Zeichenkette (r'').

Beispiel P-1. Erstellen einer Engine für eine SQLite-Datenbank
from sqlalchemy import create_engine
engine = create_engine('sqlite:///cookies.db')
engine2 = create_engine('sqlite:///:memory:')
engine3 = create_engine('sqlite:////home/cookiemonster/cookies.db')
engine4 = create_engine('sqlite:///c:\\Users\\cookiemonster\\cookies.db')
Hinweis

Die Funktion create_engine gibt eine Instanz einer Engine zurück; sie öffnet jedoch erst dann eine Verbindung, wenn eine Aktion aufgerufen wird, die eine Verbindung erfordert, wie z. B. eine Abfrage.

Mit erstellen wir eine Engine für eine lokale PostgreSQL-Datenbank namens mydb. Wir beginnen mit dem Import der Funktion create_engine aus dem Basispaket sqlalchemy. Anschließend verwenden wir diese Funktion, um eine Engine-Instanz zu erstellen. In Beispiel P-2 wird dir auffallen, dass ich postgresql+psycopg2 als Engine- und Dialektkomponente des Verbindungsstrings verwende, obwohl es auch mit postgres funktioniert. Das liegt daran, dass ich lieber explizit als implizit verwende, wie im Zen of Python empfohlen.

Beispiel P-2. Erstellen einer Engine für eine lokale PostgreSQL-Datenbank
from sqlalchemy import create_engine
engine = create_engine('postgresql+psycopg2://username:password@localhost:' \
                       '5432/mydb')

Jetzt schauen wir uns eine MySQL-Datenbank auf einem entfernten Server an. In Beispiel P-3 siehst du, dass wir nach dem Verbindungsstring einen Schlüsselwort-Parameter haben, pool_recycle, mit dem wir festlegen, wie oft die Verbindungen recycelt werden sollen.

Beispiel P-3. Erstellen einer Engine für eine entfernte MySQL-Datenbank
from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://cookiemonster:chocolatechip'
                       '@mysql01.monster.internal/cookies', pool_recycle=3600)
Vorsicht

Standardmäßig schließt MySQL Verbindungen, die länger als acht Stunden inaktiv sind. Um dieses Problem zu umgehen, kannst du pool_recycle=3600 verwenden, wenn du eine Engine erstellst, wie in Beispiel P-3 gezeigt.

Einige optionale Schlüsselwörter für die Funktion create_engine sind:

echo

Diese protokolliert die von der Engine verarbeiteten Aktionen, wie z.B. SQL-Anweisungen und ihre Parameter. Der Standardwert ist false.

encoding

Diese definiert die von SQLAlchemy verwendete String-Kodierung. Der Standardwert ist utf-8, und die meisten DBAPIs unterstützen diese Kodierung standardmäßig. Sie definiert nicht den Kodierungstyp, der von der Backend-Datenbank selbst verwendet wird.

isolation_level

Diese weist SQLAlchemy an, einen bestimmten Isolation-Level zu verwenden. Für PostgreSQL mit Psycopg2 stehen beispielsweise die Optionen READ COMMITTED, READ UNCOMMITTED, REPEATABLE READ, SERIALIZABLE und AUTOCOMMIT zur Verfügung, wobei der Standardwert READ COMMITTED ist. PyMySQL verfügt über dieselben Optionen, wobei der Standardwert REPEATABLE READ für InnoDB-Datenbanken ist.

Hinweis

Mit dem Schlüsselwortargument isolation_level kannst du den Isolation-Level für eine bestimmte DBAPI festlegen. In Dialekten wie Psycopg2, die diese Methode unterstützen, funktioniert dies genauso wie über ein Schlüssel-Wert-Paar im Verbindungsstring.

pool_recycle

Diese recycelt oder beendet die Datenbankverbindungen in regelmäßigen Abständen. Das ist für MySQL wichtig, weil es die bereits erwähnten Timeouts für Verbindungen gibt. Der Standardwert ist -1, was bedeutet, dass es keine Zeitüberschreitung gibt.

Sobald eine Engine initialisiert ist, können wir eine Verbindung zur Datenbank herstellen. Dazu rufen wir die Methode connect() für die Engine auf, wie hier gezeigt:

from sqlalchemy import create_engine
engine = create_engine('mysql+pymysql://cookiemonster:chocolatechip' \
                       '@mysql01.monster.internal/cookies', pool_recycle=3600)
connection = engine.connect()

Jetzt, da wir eine Datenbankverbindung haben, können wir entweder SQLAlchemy Core oder den ORM verwenden. In Teil I werden wir uns mit SQLAlchemy Core beschäftigen und lernen, wie du deine Datenbank definierst und abfragst.

Get Essential SQLAlchemy, 2. Auflage now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.