Ubuntu 14.04 Trusty Tahr
Ubuntu 12.04 Precise Pangolin
SQLAlchemy ist ein Objekt-relationaler Mapper (ORM) und eine SQL-Werkzeugsammlung für Python.
SQLAlchemy legt sich dabei als Zwischenschicht zwischen die Anwendung und die relationale Datenbank. Der Vorteil ist dabei, dass sich via SQLAlchemy alle unterstützten Datenbanken einheitlich ansprechen lassen, da die Unterschiede in den SQL-Dialekten durch das Programm „ausgeglichen“ werden. Das ORM-Modul gilt als extrem leistungsfähig und ermöglicht auch komplexe „Mappings“ zwischen einer Datenbank und Python-Objekten.
SQLAlchemy unterstützt eine Reihe von relationalen Datenbanken, wie z.B. SQLite, MySQL und PostgreSQL aus dem OpenSource Lager, aber auch proprietäre Datenbanken wie Orcale und MS SQL Server finden Unterstützung. Da die Anzahl der unterstützten Datenbanken in der Regel mit jeder Hauptversion von SQLAlchemy steigt, sollte man für weitere Details die jeweilige Dokumentation lesen.
SQLAlchemy ist in den Paketquellen enthalten und für kann Python 3 über
python3-sqlalchemy (universe)
mit apturl
Paketliste zum Kopieren:
sudo apt-get install python3-sqlalchemy
sudo aptitude install python3-sqlalchemy
bzw. für Python 2.7:
python-sqlalchemy (universe)
mit apturl
Paketliste zum Kopieren:
sudo apt-get install python-sqlalchemy
sudo aptitude install python-sqlalchemy
installiert werden[1].
Optional kann man auch die jeweils passende Dokumentation mit installieren:
python3-sqlalchemy-doc (universe (für Python 3))
python-sqlalchemy-doc (universe (für Python 2))
mit apturl
Paketliste zum Kopieren:
sudo apt-get install python3-sqlalchemy-doc python-sqlalchemy-doc
sudo aptitude install python3-sqlalchemy-doc python-sqlalchemy-doc
Da die Version aus den Paketquellen nicht unbedingt die neuste ist bzw. nicht unbedingt die neuste „Unterversion“ ist, so dass unter Umständen Fehlerkorrekturen fehlen, kann man SQLAlchemy alternativ auch über pip installieren.
Egal ob man SQLAlchemy über die Paketquellen oder manuell installiert - die entsprechenden Python-Module für die diversen Datenbanken müssen immer nachträglich installiert werden.
Die Anbindung an SQLite ist seit Python 2.5. - und damit bei allen unterstützen Ubuntu-Versionen - in Python selbst enthalten, so dass hier keine weitere Installation notwendig ist.
Ansonsten muss man eines oder mehrere der folgenden Pakete nachinstallieren:
für MySQL benötigt man das Paket python-mysqldb.
für PostgreSQL benötigt man eines der folgenden Pakete: python-psycopg2
für MS SQLServer und Sybase: python-pymssql (universe)
Weitere mögliche Treiber, welche vielleicht nicht in den Ubuntu-Quellen zu finden sind, listet die Seite Supported DB-APIs auf.
Wie in der Einleitung bereits erwähnt besteht SQLAlchemy aus mehreren Komponenten, die unabhängig von einander genutzt werden können. Man kann also z.B. auch „nur“ eine „Engine“ oder die „SQL Expression Language“ benutzen, ohne den kompletten ORM importieren zu müssen.
Alle folgenden Befehle können direkt in der interaktiven Python-Konsole ausgeführt werden, welche man durch den Aufruf von
python3
im Terminal öffnet[2].
Die Engine , also die Anbindung an die Datenbank an sich, stellt mit die unterste Ebene der Benutzerschnittstelle von SQLAlchemy dar. Der Vorteil gegenüber einer „gewöhnlichen“ Verbindung ist, dass die Verbindung über SQLAlchemy je nach Notwendigkeit automatisch auf- und abgebaut wird und direkt auch ein Cursor-ähnliches Objekt zur Datenabfrage bereit stellt. Ebenso verwaltet SQLAlchemy automatisch mehrere Verbindungen zu einer Datenbank über den sogenannten „Connection Pool“.
Die Datenbank wird immer gemäß einem URL-ähnlichen Schema angegeben, das wie folgt aussieht:
DATENBANK://NUTZER:PASSWORD@SERVER:PORT/DATENBANKNAME
Der Port ist optional und kann weggelassen werden, so lang die Datenbank auf deren Standardport läuft.
Will sich der Benutzer otto
mit dem Passwort normal
also z.B. mit einem lokalen MySQL Datenbankserver und der Datenbank Namens test
verbinden, so sieht dies so aus:
mysql://otto:normal@localhost/test
Eine kleine Abweichung gibt es bei SQLite, da SQLite keine Benutzerverwaltung in dieser Form kennt und die Datenbank immer als lokale Datei vorliegt:
sqlite:///meine_db.db #relativer Pfad sqlite:////pfad/zu/meine_db.db #absoluter Pfad sqlite:// #keine Angaben = In-Memory Datenbank
Die Anbindung wird via SQLAlchemy so erzeugt:
1 2 | >>> from sqlalchemy import create_engine >>> engine = create_engine('sqlite:///test.db') |
Natürlich kennt create_engine
eine Vielzahl von Optionen und Parametern. Erwähnt werden soll hier aber nur echo=True
. Damit gibt sich SQLAlchemy besonders geschwätzig und gibt z.B. alle generierten SQL-Befehle auf Stdout, also in der Regel der Konsole, aus.
Nun kann über die Execute-Funktion ein SQL-Query abgesetzt werden, z.B.:
1 2 3 4 5 | >>> ergebnis = engine.execute("SELECT foo FROM bar WHERE spam = 'egg'") >>> for erg in ergebnis: ... print(erg) (Ausgabe der Ergebnisse) |
Egal ob man später das ORM-Modul oder die SQL Expression Language benutzen möchte, das Anlegen von Tabellen erfolgt in beiden Fällen gleich. Dazu speichert das Programm Daten, Schemen etc. zu Tabellen mit Hilfe sogenannter database metadata .
Im folgenden Beispiel werden die notwendigen Importe durchgeführt, im aktuellen Verzeichnis die SQLite Datenbanknamens uude.de angelegt, die Metadaten an die Engine gebunden und dann eine einfache Tabelle Namens "programme" angelegt, welche aus drei Spalten besteht:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | >>> from sqlalchemy import create_engine, MetaData, Table, Column, Integer, String >>> engine = create_engine('sqlite:///uude.db', echo=True) >>> metadata = MetaData() >>> metadata.bind = engine >>> tab = Table('programme', metadata, ... Column('id', Integer, primary_key = True), ... Column('name',String(20)), ... Column('desktop',String(10))) >>> metadata.create_all() 2016-05-22 14:55:26,465 INFO sqlalchemy.engine.base.Engine PRAGMA table_info("programme") 2016-05-22 14:55:26,465 INFO sqlalchemy.engine.base.Engine () 2016-05-22 14:55:26,466 INFO sqlalchemy.engine.base.Engine CREATE TABLE programme ( id INTEGER NOT NULL, name VARCHAR(20), desktop VARCHAR(10), PRIMARY KEY (id) ) 2016-05-22 14:55:26,466 INFO sqlalchemy.engine.base.Engine () 2016-05-22 14:55:26,476 INFO sqlalchemy.engine.base.Engine COMMIT |
Wie man sieht gibt SQLAlchemy durch das Parameter echo=True
die abgesetzten SQL-Befehle in der Konsole aus. Der Befehl metadata.create_all()
legt dabei letztendlich die Tabelle an. Per Voreinstellung wird dabei immer zuerst automatisch geprüft, ob die Tabelle existiert, d.h. bestehende Daten werden nie gelöscht.
SQLAlchemy bietet auch die Möglichkeit, eine existierende Tabelle in die Metadaten zu übernehmen. Angenommen, in der gleichen Datenbank gäbe es bereits eine Tabelle "distributionen". Dann würde der Befehl
1 | >>> tab2 = Table('distributionen', metadata, autoload=True) |
diese automatisch tab2
zuordnen.
Nach dem Anlegen von Metadaten bzw. der Zuordnung zu einer Variablen sind die einzelnen Spalten einer Datenbank direkt ansprechbar. Im Falle der Tabelle "tab" und der Spalte "id" zum Beispiel so:
1 2 | >>> tab.c.id Column('id', Integer(), table=<programme>, primary_key=True, nullable=False) |
Das c
ist dabei die Kurzform für "Column".
Die SQL Expression Language ist, vereinfacht ausgedrückt, die „pythonische“ Variante von SQL. Das heißt es gibt diverse Python-Klassen und Funktionen, die die üblichen SQL-Befehl darstellen. Dies wird im folgenden anhand einiger kurzer Beispiele gezeigt.
Ausgehend von der weiter oben angelegten Tabelle wird diese mit ein paar Datensätzen befüllt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | >>> ergebnis = engine.execute(tab.insert(), name='Gedit', desktop='GNOME') 2016-05-22 14:57:47,165 INFO sqlalchemy.engine.base.Engine INSERT INTO programme (name, desktop) VALUES (?, ?) 2016-05-22 14:57:47,165 INFO sqlalchemy.engine.base.Engine ('Gedit', 'GNOME') 2016-05-22 14:57:47,165 INFO sqlalchemy.engine.base.Engine COMMIT >>> engine.execute(tab.insert(), name='Kate', desktop='KDE') 2016-05-22 14:58:12,056 INFO sqlalchemy.engine.base.Engine INSERT INTO programme (name, desktop) VALUES (?, ?) 2016-05-22 14:58:12,056 INFO sqlalchemy.engine.base.Engine ('Kate', 'KDE') 2016-05-22 14:58:12,057 INFO sqlalchemy.engine.base.Engine COMMIT <sqlalchemy.engine.result.ResultProxy object at 0x7f1212641c90> >>> conn = engine.connect() >>> conn.execute(tab.insert(), [ ... {'name': 'Evolution', 'desktop': 'GNOME'}, ... {'name': 'KOffice', 'desktop': 'KDE'}, ... {'name': 'Thunar', 'desktop': 'Xfce'}]) 2016-05-22 14:59:13,295 INFO sqlalchemy.engine.base.Engine INSERT INTO programme (name, desktop) VALUES (?, ?) 2016-05-22 14:59:13,295 INFO sqlalchemy.engine.base.Engine (('Evolution', 'GNOME'), ('KOffice', 'KDE'), ('Thunar', 'Xfce')) 2016-05-22 14:59:13,295 INFO sqlalchemy.engine.base.Engine COMMIT <sqlalchemy.engine.result.ResultProxy object at 0x7f1212641f50> >>> conn.close() |
Wie man sieht kennt SQLAlchemy sowohl die explizite (mit connection
) und implizite (ohne connection
) Ausführung von Befehlen, ebenso kann das Ergebnis, der sogenannte "ResultProxy" einer Variablen zugeordnet werden, wie im ersten Befehl. Außerdem ist zu sehen, dass SQLAlchemy standardmäßig im „Auto-Commit“ Modus arbeitet, bei dem Befehle direkt in der Datenbank ausgeführt werden. Dieses Verhalten lässt sich natürlich durch das Setzen der entsprechenden Option ändern.
Da die Datenbank nun ein wenig Inhalt erhalten hat, können auch Abfragen durchgeführt werden:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | >>> from sqlalchemy import select >>> query = select([tab.c.name,tab.c.desktop]) >>> ergebnis = engine.execute(query) 2016-05-22 15:00:07,716 INFO sqlalchemy.engine.base.Engine SELECT programme.name, programme.desktop FROM programme 2016-05-22 15:00:07,716 INFO sqlalchemy.engine.base.Engine () >>> for erg in ergebnis: ... print(erg['name'], erg['desktop']) ... Gedit GNOME Kate KDE Evolution GNOME KOffice KDE Thunar Xfce #nur GNOME Programme wählen: >>> query = select([tab.c.name,tab.c.desktop]) >>> query = query.where(tab.c.desktop == 'GNOME') >>> engine.execute(query).fetchall() 2016-05-22 15:01:18,970 INFO sqlalchemy.engine.base.Engine SELECT programme.name, programme.desktop FROM programme WHERE programme.desktop = ? 2016-05-22 15:01:18,970 INFO sqlalchemy.engine.base.Engine ('GNOME',) [(u'Gedit', u'GNOME'), (u'Evolution', u'GNOME')] |
Die Beispiele stellen natürlich nur einen Bruchteil der Funktionalität und Leistungsfähigkeit der SQL Expression Language dar. Viele weitere Beispiele findet man in der weiter oben verlinkten Dokumenation bzw. in dem dort befindlichen Tutorial.
Der Objekt-Relationale Mapper von SQLAlchemy ist eines der leistungsfähigsten Module. Mit seiner Hilfe können Tabellen (bzw. Spalten) von relationalen Datenbanken auf ein Python Objekt bzw. eine Python Klasse „gemappt“ d.h. abgebildet werden. Eine grundlegenden Einführung in den ORM findet man in der Dokumentation.
Das Arbeiten mit dem ORM erfolgt grundsätzlich in drei Schritten:
als erstes wird ein Mapper angelegt
dann wird eine sogenannte Session gestartet
nun können Abfrage gemacht werden, Einträge angelegt werden etc.
Im folgenden Beispiel wird ein sehr einfaches Mapping angelegt. Der Mapper von SQLAlchemy ist wesentlich leistungsfähiger und unterstützt unter anderem auch Relationen, Rückwärtsreferenzen, Joins, Vererbung etc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | >>> class Programme(object): ... pass ... >>> from sqlalchemy.orm import mapper >>> mapper(Programme, tab) <Mapper at 0x7f1212641850; Programme> >>> neues_programm = Programme() >>> neues_programm.name = 'Totem' >>> neues_programm.desktop = 'GNOME' >>> neues_programm.desktop 'GNOME' >>> from sqlalchemy.orm import sessionmaker >>> Session = sessionmaker(bind=engine) >>> session = Session() >>> session.add(neues_programm) >>> session.commit() 2016-05-22 15:04:11,216 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) 2016-05-22 15:04:11,216 INFO sqlalchemy.engine.base.Engine INSERT INTO programme (name, desktop) VALUES (?, ?) 2016-05-22 15:04:11,216 INFO sqlalchemy.engine.base.Engine ('Totem', 'GNOME') 2016-05-22 15:04:11,217 INFO sqlalchemy.engine.base.Engine COMMIT >>> neues_programm.id 2016-05-22 15:04:57,923 INFO sqlalchemy.engine.base.Engine BEGIN (implicit) 2016-05-22 15:04:57,924 INFO sqlalchemy.engine.base.Engine SELECT programme.id AS programme_id, programme.name AS programme_name, programme.desktop AS programme_desktop FROM programme WHERE programme.id = ? 2016-05-22 15:04:57,924 INFO sqlalchemy.engine.base.Engine (6,) 6 |
Wie man sieht reicht es, für das Mapping eine leere Klasse anzulegen. Aber natürlich kann man auch das sonst notwendige __init__
definieren sowie weitere Funktionen in der Klasse anlegen.
Abfragen sind so auch möglich:
1 2 3 4 5 6 7 8 9 10 11 | >>> ergebnis = session.query(Programme.name).filter(Programme.desktop == 'GNOME') >>> for erg in ergebnis: ... print(erg) ... 2016-05-22 15:05:39,091 INFO sqlalchemy.engine.base.Engine SELECT programme.name AS programme_name FROM programme WHERE programme.desktop = ? 2016-05-22 15:05:39,091 INFO sqlalchemy.engine.base.Engine ('GNOME',) (u'Gedit',) (u'Evolution',) (u'Totem',) |
Weitere Informationen zu Abfragen via ORM findet man in der Dokumentation.
Alle obigen Beispiele zeigen nur einige wenige Grundlagen von SQLAlchemy. Wer sich näher mit SQLAlchemy beschäftigen möchte, dem sei die sehr gute und ausführliche, offizielle Dokumentaion empfohlen, welche zwei Tutorials, viele Detailinformationen und Beispiele sowie eine umfassende API-Referenz bietet.
Diese Revision wurde am 22. Mai 2016 16:31 von noisefloor erstellt.