tags:
是的!要让 SQLAlchemy 像 Django ORM 那样优雅地在不改变数据的情况下增加字段,最好的方式是使用 Alembic 迁移工具。这就是 SQLAlchemy 世界的"Django Migrations"!
🚀 完整的工作流程
1. 项目结构和安装
1
2
3
4
5
6
7
8
|
# 安装必要包
pip install sqlalchemy alembic
# 项目结构
my_project/
├── app.py# 主应用
├── models.py# 数据模型
└── migrations/# Alembic 迁移文件(后续生成)
|
2. 初始模型定义 (models.py)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(64), unique=True)
email = Column(String(120))
def __repr__(self):
return f'<User {self.username}>'
|
3. 初始化 Alembic(就像 Django 的 makemigrations)
1
2
3
4
5
|
# 初始化 Alembic
alembic init migrations
# 配置 alembic.ini 文件中的 sqlalchemy.url
# 以及 migrations/env.py 中的 target_metadata
|
修改 migrations/env.py:
1
2
|
from models import Base
target_metadata = Base.metadata
|
4. 当你需要添加新字段时的操作
步骤 1:修改模型 (models.py)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
from sqlalchemy import Column, Integer, String, DateTime, Boolean
from datetime import datetime
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(64), unique=True)
email = Column(String(120))
# 新增的字段
phone = Column(String(20), nullable=True)# 可为空,现有数据自动设为 NULL
is_active = Column(Boolean, default=True)# 有默认值
created_at = Column(DateTime, default=datetime.now)# 时间戳默认值
|
步骤 2:生成迁移脚本(就像 Django 的 makemigrations)
1
|
alembic revision --autogenerate -m "add user profile fields"
|
步骤 3:检查生成的迁移文件
在 migrations/versions/ 目录下会生成类似这样的文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
"""add user profile fields
Revision ID: xxxxx
Revises: yyyyy
Create Date: 2024-01-01 10:00:00
"""
from alembic import op
import sqlalchemy as sa
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column('users', sa.Column('phone', sa.String(length=20), nullable=True))
op.add_column('users', sa.Column('is_active', sa.Boolean(), nullable=True, server_default='true'))
op.add_column('users', sa.Column('created_at', sa.DateTime(), nullable=True))
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column('users', 'created_at')
op.drop_column('users', 'is_active')
op.drop_column('users', 'phone')
|
步骤 4:应用迁移(就像 Django 的 migrate)
💡 实用的自动化脚本
创建一个 manage.py 文件来模仿 Django 的管理命令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#!/usr/bin/env python3
import os
import sys
from alembic.config import Config
from alembic import command
def run_migrations():
"""运行迁移"""
config = Config("alembic.ini")
command.upgrade(config, "head")
def make_migration(message):
"""创建新的迁移"""
config = Config("alembic.ini")
command.revision(config, autogenerate=True, message=message)
if __name__ == "__main__":
if sys.argv == "makemigrations":
make_migration(sys.argv)
elif sys.argv == "migrate":
run_migrations()
|
使用方式:
1
2
|
python manage.py makemigrations "add user profile fields"
python manage.py migrate
|
🎯 针对不同环境的建议
开发环境快速流程:
1
2
3
4
5
|
# 1. 改模型
# 2. 生成迁移
alembic revision --autogenerate -m "your message"
# 3. 应用迁移
alembic upgrade head
|
生产环境严谨流程:
1
2
3
4
5
6
|
# 1. 备份数据库
# 2. 改模型
# 3. 生成迁移
# 4. 审查生成的SQL
# 5. 应用迁移
alembic upgrade head
|
🔄 完整示例:从简单用户扩展到完整档案
初始用户模型:
1
2
3
4
|
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String(64))
|
添加个人信息后的模型:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class User(Base):
__tablename__ = 'users'
# 原有字段
id = Column(Integer, primary_key=True)
username = Column(String(64))
# 新增的个人信息字段
first_name = Column(String(50))
last_name = Column(String(50))
date_of_birth = Column(DateTime, nullable=True)
avatar_url = Column(String(200), nullable=True)
bio = Column(Text, nullable=True)
last_login = Column(DateTime, nullable=True)
|
✨ 核心优势
这种方式提供了与 Django ORM 类似的体验:
- ✅ 声明式模型更改
- ✅ 自动生成迁移脚本
- ✅ 保持现有数据完好无损
- ✅ 支持版本控制和回滚
- ✅ 跨数据库兼容
🚨 注意事项
- 总是先备份生产数据
- 在测试环境验证迁移
- 审查自动生成的SQL
- 准备好回滚方案
这样就实现了与 Django ORM 几乎相同的开发体验!🎉
上面运行报,需要添加设置
Alembic 设置数据库连接
`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
# alembic.ini
[alembic]
# 直接在这里写入连接字符串
script_location = migrations
sqlalchemy.url = postgresql://username:password@localhost/mydatabase
# 或者使用 MySQL
sqlalchemy.url = mysql+pymysql://username:password@localhost/mydatabase
# 或者使用 SQLite
sqlalchemy.url = sqlite:///app.db
# 示例:
# PostgreSQL: postgresql://user:pass@localhost/dbname
# MySQL: mysql+pymysql://user:pass@localhost/dbname
sqlalchemy.url = sqlite:///./test.db
[loggers]
keys = root,sqlalchemy,alembic
[handlers]
keys = console [formatter_generic] format = %(levelname)-5.5s [%(name)s] %(message)s
|