bry*_*mar 2 python postgresql sqlalchemy database-migration google-cloud-sql
试图将我的早期项目的数据库迁移到云中。尽管构建所有内容的代码都是简陋的,但是db结构和数据本身还是相当完善的。我可能会想出一种迁移所有内容(例如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)
[...]
Run Code Online (Sandbox Code Playgroud)
然后,我将此文件复制为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()
Run Code Online (Sandbox Code Playgroud)
运行此命令将产生以下错误:
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')
Run Code Online (Sandbox Code Playgroud)
显式设置for循环内的每一列都可以(例如:)category_cloud.id = c.id,但是必须有一种方法来避免必须对每个表中的每一列执行此操作。我应该如何处理?
小智 6
使用sqlalchemy核心而不是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))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
611 次 |
| 最近记录: |