gpt4 book ai didi

python - 使用SQLAlchemy迁移数据库(sqlite到Postgres CloudSQL)

转载 作者:行者123 更新时间:2023-11-29 11:54:45 30 4
gpt4 key购买 nike

尝试将我早期项目的数据库迁移到云端。尽管构建所有内容的代码很糟糕,但数据库结构和数据本身相当可靠。我可能想出一种迁移所有内容的转储方法(pgdump 等),但我对这些东西还有很多东西要学习,所以我宁愿通过逐步进行来获得经验。

来源: ~1gb sqlite 数据库文件

目标运行 Postgres v9.6 的 Google CloudSQL

已经在云数据库中创建了表,使用与 sqlite 数据库相同的模式和表名。不担心模式实现错误,因为我还没有在云中定义外键。

计划:为每个数据库创建不同的并发 SQLAlchemy 连接,然后读取 sqlite --> 写入 CloudSQL。返回并使用 SQLAlchemy 为每个表定义数据结构。 models.py 的片段:

from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base, declared_attr

Base = declarative_base()

class PublicMixin(object):
@declared_attr
def __tablename__(cls):
return cls.__name__.lower()

class Category(PublicMixin, Base):
id = Column(Integer, primary_key=True)
name = Column(String)

class Player(PublicMixin, Base):
id = Column(Integer, primary_key=True)
name = Column(String)
username = Column(String)
notes = Column(String)
[...]

然后我将此文件复制为 models_lite.py,这样我就可以导入每个模型而不会产生干扰。这是我尝试作为概念证明运行的 migration.py 文件:

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import Base, Category, Player
from models_sqlite import Base as Base_lite, Category as Category_lite, Player as Player_lite

# SQLite db
engine_lite = create_engine('sqlite:///mydb.sqlite')
Base_lite.metadata.bind = engine_lite
LiteSession = sessionmaker()
LiteSession.bind = engine_lite
session_lite = LiteSession()

# CloudSQL, via local proxy
engine_cloud = create_engine('postgresql+psycopg2://USER:PW@/DBNAME?host=/cloudsql/INSTANCE')
Base.metadata.bind = engine_cloud
CloudSession = sessionmaker()
CloudSession.bind = engine_cloud
session_cloud = CloudSession()

category_lite = session_lite.query(Category_lite).all()
category_cloud = Category()

for c in category_lite:
category_cloud = c
session_cloud.add(category_cloud)

session_cloud.commit()

运行它会产生以下错误:

File "postgres migration.py", line 68, in <module>
session_cloud.add(category_cloud)
[...]
sqlalchemy.exc.InvalidRequestError: Object '<Category at 0x11141b908>' is already attached to session '1' (this is '2')

for 循环中显式设置每一列是可行的(即:category_cloud.id = c.id),但必须有一种方法来避免必须这样做对于每个表中的每一列。我应该如何处理这个问题?

最佳答案

这种数据传输操作用sqlalchemy core比orm更容易实现。如果数据库数据只是要立即写入另一个数据库,那么将数据库数据映射到对象在这里没有任何好处,它只会增加复杂性并减慢速度。下面的代码会遍历Base中的每一张表,选择sqlite数据库中的所有列,一次一张地写入云数据库。

from sqlalchemy import create_engine, select
from models import Base

engine_lite = create_engine('sqlite:///mydb.sqlite')
engine_cloud = create_engine('postgresql+psycopg2://USER:PW@/DBNAME?host=/cloudsql/INSTANCE')

with engine_lite.connect() as conn_lite:
with engine_cloud.connect() as conn_cloud:
for table in Base.metadata.sorted_tables:
data = [dict(row) for row in conn_lite.execute(select(table.c))]
conn_cloud.execute(table.insert().values(data))

关于python - 使用SQLAlchemy迁移数据库(sqlite到Postgres CloudSQL),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55756491/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com