我正在寻找一种使用Python转储PostgreSQL数据库模式的方法。理想情况下,结果可能是.sql
转储或SQLAlchemy稍后可以使用的任何其他格式,以便从该模式创建新数据库。
我使用SQLAlchemy MetaData class创建了这个实验:
from sqlalchemy import MetaData, create_engine
engine = create_engine(source_database_url)
test_engine = create_engine(test_database_url)
metadata = MetaData()
metadata.reflect(engine)
metadata.create_all(test_engine)
除了导出架构供以后使用外,这正是我想要的。因此,考虑到SQLAlchemy可以成功地反映架构并基于它创建另一个表,我希望有一种方法可以在此过程中以编程方式将其导出。
我知道我可以从代码中召唤pg_dump
和pg_restore
,但我希望避免外部依赖以及随之而来的麻烦。
有没有办法通过SQLAlchemy或其他Python库实现这一目标?
答案 0 :(得分:2)
进一步挖掘后,我发现了helpful section from SQLAlchemy docs。 因此,从该代码片段开始,我创建了以下类:
import io
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import sessionmaker
class SchemaDump(object):
def __init__(self, db_url, schema_file_path):
self.db_url = db_url
self.schema_file_path = schema_file_path
self.buf = io.BytesIO()
def dump_shema(self):
engine = create_engine(self.db_url)
metadata = MetaData()
metadata.reflect(engine)
def dump(sql, *multiparams, **params):
f = sql.compile(dialect=engine.dialect)
self.buf.write(str(f).encode('utf-8'))
self.buf.write(b';\n')
new_engine = create_engine(self.db_url, strategy='mock', executor=dump)
metadata.create_all(new_engine, checkfirst=True)
with io.open(self.schema_file_path, 'wb+') as schema:
schema.write(self.buf.getvalue())
这仍然相当粗略,但主要思想是捕获sql.compile(dialect=engine.dialect)
中buf
返回的原始SQL语句并将其写入文件。
我写了一个同样粗略的类来从上面的类创建的.sql
转储中恢复数据库:
import io
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
class RestoreSchema(object):
def __init__(self, db_url, schema_file_path):
self.db_url = db_url
self.schema_file_path = schema_file_path
def restore_schema(self):
raw_schema = ''
with io.open(self.schema_file_path) as sql_schema:
raw_schema = sql_schema.read()
engine = create_engine(self.db_url)
Session = sessionmaker(bind=engine)
session = Session()
conn = engine.connect()
transaction = conn.begin()
try:
conn.execute(raw_schema)
transaction.commit()
except Exception as e:
transaction.rollback()
raise e
finally:
session.close()
您仍然需要担心表格是否已经存在等等,但效果与我的问题中的代码段完全相同。