Come creare un nuovo database utilizzando SQLAlchemy?


103

Utilizzando SQLAlchemy, viene creato un oggetto Engine in questo modo:

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

L'accesso enginenon riesce se il database specificato nell'argomento a create_engine(in questo caso mydb) non esiste. È possibile dire a SQLAlchemy di creare un nuovo database se il database specificato non esiste?


2
Creare un nuovo database o solo tabelle? Non ho incontrato molti ORM che creano effettivamente database.
Noufal Ibrahim

4
Ho trovato questo
Noufal Ibrahim,

Risposte:


97

Su postgres, normalmente sono presenti tre database per impostazione predefinita. Se sei in grado di connetterti come superutente (ad es. Il postgresruolo), puoi connetterti ai database postgreso template1. L'impostazione predefinita pg_hba.conf consente solo all'utente unix nominato postgresdi utilizzare il postgresruolo, quindi la cosa più semplice è diventare quell'utente. In ogni caso, crea un motore come al solito con un utente che abbia i permessi per creare un database:

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

engine.execute()Tuttavia, non è possibile utilizzarlo , poiché postgres non consente di creare database all'interno di transazioni e sqlalchemy cerca sempre di eseguire query in una transazione. Per aggirare questo problema, ottieni la connessione sottostante dal motore:

>>> conn = engine.connect()

Ma la connessione sarà ancora all'interno di una transazione, quindi devi terminare la transazione aperta con commit:

>>> conn.execute("commit")

E puoi quindi procedere alla creazione del database utilizzando il comando PostgreSQL appropriato per esso.

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

3
Questo ha funzionato bene per me. Come nota a margine, quando l'ho fatto conn.execute('drop database DBWithCaps')ho avuto problemi con il non riconoscere i cappucci. conn.execute('drop database "DBWithCaps"')(con le virgolette) ha funzionato bene.
KobeJohn

So che PostgreSQL si aspetta tutte le entità in minuscolo, a meno che non vengano citate. Quindi, se hai creato un campo usando MyColumn, alcuni DB lo prenderanno come mycolumn. In altre parole, non sono sicuro di come hai creato la tua tabella, ma se è stata creata usando le virgolette, farà distinzione tra maiuscole e minuscole, quindi quando ti accederai in un'istruzione SQL avrai bisogno anche delle virgolette.
Guyarad

119

SQLAlchemy-Utils fornisce tipi di dati personalizzati e varie funzioni di utilità per SQLAlchemy. Puoi installare la versione ufficiale più recente usando pip:

pip install sqlalchemy-utils

Gli helper del database includono una create_databasefunzione:

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
Ottengo questo errore quando prova questo codeblock esatto: psycopg2.OperationalError: fe_sendauth: no password supplied. Quando uso "postgres://test:abc123@localhost:5432/test"ottengopsycopg2.OperationalError: FATAL: password authentication failed for user "test"
Guus

Scusa per lo spam, ma ho provato a cambiare la porta a 9000 e ora ottengo questo:"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

È possibile evitare la gestione manuale delle transazioni durante la creazione del database fornendo isolation_level='AUTOCOMMIT'alla create_enginefunzione:

import sqlalchemy

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

Inoltre, se non sei sicuro che il database non esista, c'è un modo per ignorare l'errore di creazione del database dovuto all'esistenza sopprimendo l' sqlalchemy.exc.ProgrammingErroreccezione:

import contextlib
import sqlalchemy.exc

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

Sembra che tu non possa connetterti a un server progres senza specificare un database, quindi probabilmente vorrai connetterti al database predefinito "postgres" per eseguire i comandi di creazione del db, altrimenti proverà a connettersi all'utente predefinito " "database e lamentarsi se non esiste.
Acorn

0

Si prega di notare che non sono riuscito a ottenere i suggerimenti di cui sopra database_existsperché ogni volta che controllo se il database esiste, in caso contrario database_exists(engine.url):ottengo questo errore:

InterfaceError ('(pyodbc.InterfaceError) (\' 28000 \ ', u \' [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server] Accesso non riuscito per l'utente \\ 'myUser \\'. (18456) (SQLDriverConnect); [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server] Impossibile aprire il database "MY_DATABASE" richiesto dall'account di accesso. Accesso non riuscito. (4060); [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server] Accesso non riuscito per l'utente \\ 'myUser \\'. (18456); [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server] Impossibile aprire il database "MY_DATABASE" richiesto dall'account di accesso . Accesso non riuscito. (4060) \ ')',)

Inoltre contextlib/suppressnon funzionava e non lo sto usando, postgresquindi ho finito per ignorare l'eccezione se il database esiste già con SQL Server:

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))  
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.