如何使用SQLAlchemy创建新数据库?


103

使用SQLAlchemy,将创建一个Engine对象,如下所示:

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

engine如果在参数create_engine(在这种情况下为mydb)中指定的数据库不存在,则访问将失败。如果指定的数据库不存在,是否可以告诉SQLAlchemy创建一个新数据库?


2
创建一个新数据库还是仅创建表?我没有碰到很多实际创建数据库的ORM。
Noufal Ibrahim

4
我确实找到了这个
Noufal Ibrahim

Answers:


97

在postgres上,默认情况下通常存在三个数据库。如果您能够以超级用户身份(例如,postgres角色)进行连接,则可以连接到postgrestemplate1数据库。默认的pg_hba.conf仅允许名为unix的用户postgres使用该postgres角色,因此最简单的方法就是成为该用户。无论如何,使用有权创建数据库的用户照常创建引擎:

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

engine.execute()但是,您无法使用,因为postgres不允许您在事务内部创建数据库,而sqlalchemy始终尝试在事务中运行查询。要解决此问题,请从引擎获取基础连接:

>>> conn = engine.connect()

但是连接仍将在事务内部,因此您必须使用以下命令结束打开的事务commit

>>> conn.execute("commit")

然后,您可以使用适当的PostgreSQL命令继续创建数据库。

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

3
这对我来说很好。附带一提,当我这样做时,conn.execute('drop database DBWithCaps')我遇到了无法识别上限的问题。conn.execute('drop database "DBWithCaps"')(带有引号)效果很好。
神户约翰·约翰逊,2013年

我知道PostgreSQL期望所有实体都使用小写,除非引用。因此,如果您使用MyColumn创建了一个字段,则某些数据库会将其视为mycolumn。换句话说,不知道如何创建您的表,但如果它是用引号创建的,它区分大小写的,所以当你在一个SQL语句访问它,你需要引号为好。
Guyarad

119

SQLAlchemy-UtilsSQLAlchemy提供自定义数据类型和各种实用程序功能。您可以使用pip安装最新的正式版本:

pip install sqlalchemy-utils

数据库的助手包括create_database功能:

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
尝试使用此确切的代码块时,出现此错误:psycopg2.OperationalError: fe_sendauth: no password supplied。使用时,"postgres://test:abc123@localhost:5432/test"我得到psycopg2.OperationalError: FATAL: password authentication failed for user "test"
Guus

抱歉,该邮件为垃圾邮件,但我尝试将端口更改为9000,现在我得到了:"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

通过提供isolation_level='AUTOCOMMIT'以下create_engine功能,可以避免在创建数据库时进行手动事务管理:

import sqlalchemy

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

另外,如果不确定数据库是否存在,可以通过抑制sqlalchemy.exc.ProgrammingError异常来忽略由于存在而导致的数据库创建错误:

import contextlib
import sqlalchemy.exc

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

似乎如果不指定数据库就无法连接到Progres服务器,因此您可能要连接到默认的“ postgres”数据库来执行db创建命令,否则它将尝试连接到默认的“ user”用户”数据库,并抱怨它是否不存在。
橡子

0

请注意,我无法获得上述建议,database_exists因为每当我检查数据库是否存在时,如果没有database_exists(engine.url):,就会出现此错误:

InterfaceError('(pyodbc.InterfaceError)(\'28000 \',u \'[28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server]用户\\'myUser \\'的登录失败。(18456) (SQLDriverConnect); [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server]无法打开登录请求的数据库“ MY_DATABASE”。登录失败。(4060); [28000] [Microsoft] [SQL Server Native客户端11.0] [SQL Server]用户\\'myUser \\'的登录失败。(18456); [28000] [Microsoft] [SQL Server Native Client 11.0] [SQL Server]无法打开登录请求的数据库“ MY_DATABASE” 。登录失败。(4060)\')',)

同样contextlib/suppress也无法正常工作,并且我没有使用,postgres因此如果数据库恰好已存在于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))  
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.