Wie erstelle ich eine neue Datenbank mit SQLAlchemy?


103

Mit SQLAlchemy wird ein Engine-Objekt wie folgt erstellt:

from sqlalchemy import create_engine
engine = create_engine("postgresql://localhost/mydb")

Der Zugriff engineschlägt fehl, wenn die im Argument to create_engine(in diesem Fall mydb) angegebene Datenbank nicht vorhanden ist. Kann SQLAlchemy angewiesen werden, eine neue Datenbank zu erstellen, wenn die angegebene Datenbank nicht vorhanden ist?


2
Neue Datenbank erstellen oder nur Tabellen? Ich bin nicht auf viele ORMs gestoßen, die tatsächlich Datenbanken erstellen.
Noufal Ibrahim


Antworten:


97

Auf Postgres sind normalerweise standardmäßig drei Datenbanken vorhanden. Wenn Sie als Superuser eine Verbindung herstellen können (z. B. die postgresRolle), können Sie eine Verbindung zu den Datenbanken postgresoder herstellen template1. Die Standard-Datei pg_hba.conf erlaubt nur dem genannten Unix-Benutzer postgres, die postgresRolle zu verwenden. Am einfachsten ist es also, nur dieser Benutzer zu werden. Erstellen Sie auf jeden Fall wie gewohnt eine Engine mit einem Benutzer, der über die Berechtigung zum Erstellen einer Datenbank verfügt:

>>> engine = sqlalchemy.create_engine("postgres://postgres@/postgres")

Sie können dies engine.execute()jedoch nicht verwenden , da Sie mit postgres keine Datenbanken innerhalb von Transaktionen erstellen können und sqlalchemy immer versucht, Abfragen in einer Transaktion auszuführen. Um dies zu umgehen, rufen Sie die zugrunde liegende Verbindung von der Engine ab:

>>> conn = engine.connect()

Die Verbindung befindet sich jedoch weiterhin innerhalb einer Transaktion. Sie müssen die geöffnete Transaktion daher mit einem commitfolgenden Ergebnis beenden :

>>> conn.execute("commit")

Anschließend können Sie die Datenbank mit dem entsprechenden PostgreSQL-Befehl erstellen.

>>> conn.execute("create database test")
>>> conn.close()

3
Das hat bei mir gut funktioniert. Als Randnotiz hatte conn.execute('drop database DBWithCaps')ich Probleme damit, die Kappen nicht zu erkennen. conn.execute('drop database "DBWithCaps"')(mit den Anführungszeichen) hat gut funktioniert.
KobeJohn

Ich weiß, dass PostgreSQL alle Entitäten in Kleinbuchstaben erwartet, sofern nicht anders angegeben. Wenn Sie also ein Feld mit MyColumn erstellt haben, wird es von einigen DBs als mycolumn verwendet. Mit anderen Worten, Sie sind sich nicht sicher, wie Sie Ihre Tabelle erstellt haben, aber wenn sie mit Anführungszeichen erstellt wurde, wird zwischen Groß- und Kleinschreibung unterschieden. Wenn Sie also in einer SQL-Anweisung darauf zugreifen, benötigen Sie auch die Anführungszeichen.
Guyarad

119

SQLAlchemy-Utils bietet benutzerdefinierte Datentypen und verschiedene Dienstprogrammfunktionen für SQLAlchemy. Sie können die neueste offizielle Version mit pip installieren:

pip install sqlalchemy-utils

Die Datenbankhelfer enthalten eine create_databaseFunktion:

from sqlalchemy import create_engine
from sqlalchemy_utils import database_exists, create_database

engine = create_engine("postgres://localhost/mydb")
if not database_exists(engine.url):
    create_database(engine.url)

print(database_exists(engine.url))

2
Ich erhalte diese Fehlermeldung, wenn ich genau diesen Codeblock versuche : psycopg2.OperationalError: fe_sendauth: no password supplied. Bei der Verwendung "postgres://test:abc123@localhost:5432/test"bekomme ichpsycopg2.OperationalError: FATAL: password authentication failed for user "test"
Guus

Entschuldigung für den Spam, aber ich habe versucht, den Port auf 9000 zu ändern und jetzt bekomme ich Folgendes:"postgres://test:abc123@localhost:9000/test" psycopg2.OperationalError: server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request.
Guus

9

Es ist möglich , manuelles Transaktionsmanagement zu vermeiden , während Datenbank erstellen , indem sie isolation_level='AUTOCOMMIT'auf create_engineFunktion:

import sqlalchemy

with sqlalchemy.create_engine(
    'postgresql:///postgres',
    isolation_level='AUTOCOMMIT'
).connect() as connection:
    connection.execute('CREATE DATABASE my_database')

Auch wenn Sie nicht sicher sind, ob die Datenbank nicht vorhanden ist, können Sie den Fehler bei der Datenbankerstellung aufgrund der Existenz ignorieren, indem Sie die sqlalchemy.exc.ProgrammingErrorAusnahme unterdrücken :

import contextlib
import sqlalchemy.exc

with contextlib.suppress(sqlalchemy.exc.ProgrammingError):
    # creating database as above

Es scheint, dass Sie keine Verbindung zu einem Progres-Server herstellen können, ohne eine Datenbank anzugeben. Daher möchten Sie wahrscheinlich eine Verbindung zur Standarddatenbank "postgres" herstellen, um die Befehle zum Erstellen der Datenbank auszuführen. Andernfalls wird versucht, eine Verbindung zum Standardbenutzer herzustellen "Datenbank und beschweren, wenn es nicht existiert.
Eichel

0

Bitte beachten Sie, dass ich die oben genannten Vorschläge nicht erhalten konnte, database_existsda bei jeder Überprüfung, ob die Datenbank vorhanden ist, die folgende database_exists(engine.url):Fehlermeldung angezeigt wird:

InterfaceError ('(pyodbc.InterfaceError) (\' 28000 \ ', u \' [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server] Anmeldung für Benutzer \\ 'myUser \\' fehlgeschlagen. (18456) (SQLDriverConnect); [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server] Die von der Anmeldung angeforderte Datenbank "MY_DATABASE" kann nicht geöffnet werden. Die Anmeldung ist fehlgeschlagen. (4060); [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server] Anmeldung für Benutzer \\ 'myUser \\' fehlgeschlagen. (18456); [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server] Die vom Login angeforderte Datenbank "MY_DATABASE" kann nicht geöffnet werden Die Anmeldung ist fehlgeschlagen. (4060) \ ')',)

Funktionierte auch contextlib/suppressnicht und ich verwende es nicht. Daher postgreshabe ich dies getan, um die Ausnahme zu ignorieren, wenn die Datenbank zufällig bereits mit SQL Server vorhanden ist:

import logging
import sqlalchemy

logging.basicConfig(filename='app.log', format='%(asctime)s-%(levelname)s-%(message)s', level=logging.DEBUG)
engine = create_engine('mssql+pyodbc://myUser:mypwd@localhost:1234/MY_DATABASE?driver=SQL+Server+Native+Client+11.0?trusted_connection=yes', isolation_level = "AUTOCOMMIT")

try: 
    engine.execute('CREATE DATABASE ' + a_database_name)
except Exception as db_exc:
    logging.exception("Exception creating database: " + str(db_exc))  
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.