Comment créer une nouvelle base de données en utilisant SQLAlchemy?

103

En utilisant SQLAlchemy, un objet Engine est créé comme ceci:

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

L'accès engineéchoue si la base de données spécifiée dans l'argument à create_engine(dans ce cas, mydb) n'existe pas. Est-il possible de dire à SQLAlchemy de créer une nouvelle base de données si la base de données spécifiée n'existe pas?

Anand Chitipothu
la source
2
Créer une nouvelle base de données ou simplement des tables? Je n'ai pas rencontré beaucoup d'ORM qui créent réellement des bases de données.
Noufal Ibrahim
4
J'ai trouvé ça
Noufal Ibrahim

Réponses:

98

Sur postgres, trois bases de données sont normalement présentes par défaut. Si vous pouvez vous connecter en tant que superutilisateur (par exemple, le postgresrôle), vous pouvez vous connecter aux bases de données postgresou template1. Le pg_hba.conf par défaut permet uniquement à l'utilisateur Unix nommé postgresd'utiliser le postgresrôle, donc le plus simple est de devenir cet utilisateur. Dans tous les cas, créez un moteur comme d'habitude avec un utilisateur qui a les autorisations pour créer une base de données:

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

engine.execute()Cependant, vous ne pouvez pas utiliser , car postgres ne vous permet pas de créer des bases de données dans des transactions et sqlalchemy essaie toujours d'exécuter des requêtes dans une transaction. Pour contourner cela, obtenez la connexion sous-jacente du moteur:

>>> conn = engine.connect()

Mais la connexion sera toujours à l'intérieur d'une transaction, vous devez donc terminer la transaction ouverte avec un commit:

>>> conn.execute("commit")

Et vous pouvez ensuite créer la base de données en utilisant la commande PostgreSQL appropriée.

>>> conn.execute("create database test")
>>> conn.close()
SingleNegationElimination
la source
3
Cela a bien fonctionné pour moi. En passant, quand je l'ai fait, conn.execute('drop database DBWithCaps')j'ai eu des problèmes avec le fait de ne pas reconnaître les casquettes. conn.execute('drop database "DBWithCaps"')(avec les guillemets) a bien fonctionné.
KobeJohn
Je sais que PostgreSQL attend toutes les entités en minuscules, sauf si elles sont citées. Donc, si vous avez créé un champ en utilisant MyColumn, certains DB le prendront comme mycolumn. En d'autres termes, vous ne savez pas comment vous avez créé votre table, mais si elle a été créée à l'aide de guillemets, elle sera sensible à la casse, donc lorsque vous y accédez dans une instruction SQL, vous aurez également besoin des guillemets.
guyarad
120

SQLAlchemy-Utils fournit des types de données personnalisés et diverses fonctions utilitaires pour SQLAlchemy. Vous pouvez installer la version officielle la plus récente en utilisant pip:

pip install sqlalchemy-utils

Les assistants de base de données incluent une create_databasefonction:

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))
buhtz
la source
2
Je reçois cette erreur lorsque vous essayez cette codeblock exacte: psycopg2.OperationalError: fe_sendauth: no password supplied. Lors de l'utilisation "postgres://test:abc123@localhost:5432/test"je reçoispsycopg2.OperationalError: FATAL: password authentication failed for user "test"
Guus
Désolé pour le spam, mais j'ai essayé de changer le port à 9000 et maintenant je reçois ceci:"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

Il est possible d'éviter la gestion manuelle des transactions lors de la création de la base de données en fournissant isolation_level='AUTOCOMMIT'à la create_enginefonction:

import sqlalchemy

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

De plus, si vous n'êtes pas sûr que la base de données n'existe pas, il existe un moyen d'ignorer l'erreur de création de base de données due à l'existence en supprimant l' sqlalchemy.exc.ProgrammingErrorexception:

import contextlib
import sqlalchemy.exc

with contextlib.suppress(sqlalchemy.exc.ProgrammingError):
    # creating database as above
renskiy
la source
Il semble que vous ne pouvez pas vous connecter à un serveur progres sans spécifier une base de données, vous voudrez donc probablement vous connecter à la base de données "postgres" par défaut pour exécuter les commandes de création de db, sinon il essaiera de se connecter à l'utilisateur par défaut " "base de données et se plaindre si elle n'existe pas.
Acorn
0

Veuillez noter que je n'ai pas pu obtenir les suggestions ci-dessus avec database_existscar chaque fois que je vérifie si la base de données existe en utilisant sinon, database_exists(engine.url):j'obtiens cette erreur:

InterfaceError ('(pyodbc.InterfaceError) (\' 28000 \ ', u \' [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server] La connexion a échoué pour l'utilisateur \\ 'myUser \\'. (18456) (SQLDriverConnect); [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server] Impossible d'ouvrir la base de données "MY_DATABASE" demandée par la connexion. La connexion a échoué. (4060); [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server] La connexion a échoué pour l'utilisateur \\ 'myUser \\'. (18456); [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server] Impossible d'ouvrir la base de données "MY_DATABASE" demandée par la connexion . La connexion a échoué. (4060) \ ')',)

Aussi contextlib/suppressne fonctionnait pas et je ne suis pas en utilisant postgresdonc j'ai fini par faire cela pour ignorer l'exception si la base de données se produit déjà exister avec 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))  
user8128167
la source