20251026 sqlalchemy 如何像 django orm 一样 ,数据不改变情况下,增加字段

--- tags: - python - alembic - 迁移 --- 是的!要让 SQLAlchemy 像 Django ORM 那样优雅地在不改变数据的情况下增加字段,最好的方式是


tags:

  • python
  • alembic
  • 迁移

是的!要让 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)

1
alembic upgrade head

💡 实用的自动化脚本

创建一个 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 类似的体验:

  • 声明式模型更改
  • 自动生成迁移脚本
  • 保持现有数据完好无损
  • 支持版本控制和回滚
  • 跨数据库兼容

🚨 注意事项

  1. 总是先备份生产数据
  2. 在测试环境验证迁移
  3. 审查自动生成的SQL
  4. 准备好回滚方案

这样就实现了与 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
使用 Hugo 构建
主题 StackJimmy 设计