
数据库迁移工具Aerich详解
数据库迁移工具Aerich详解
如果说数据库是应用的"心脏",那么数据库迁移就是"心脏手术"——需要精确、安全、可回滚。Aerich作为Tortoise-ORM的专用迁移工具,就像是一位经验丰富的"数据库外科医生",让我们能够安全地进行数据库结构变更。
一、Aerich简介:数据库迁移的艺术
什么是数据库迁移?
在软件开发过程中,数据库结构经常需要变更:
- 添加新表和字段
- 修改字段类型和约束
- 删除不再需要的表和字段
- 创建或删除索引
数据库迁移工具帮助我们:
- 版本控制:跟踪数据库结构的每一次变更
- 团队协作:确保所有开发者的数据库结构一致
- 部署安全:在生产环境中安全地应用数据库变更
- 回滚能力:出现问题时能够快速回滚到之前的状态
Aerich的特点
| 特性 | Aerich | Django Migrations | Alembic |
|---|---|---|---|
| ORM集成 | Tortoise-ORM专用 | Django ORM专用 | SQLAlchemy专用 |
| 异步支持 | ✅ 原生支持 | ❌ 不支持 | ✅ 支持 |
| 自动生成 | ✅ 支持 | ✅ 支持 | ✅ 支持 |
| 学习曲线 | 🟢 简单 | 🟢 简单 | 🟡 中等 |
| 配置复杂度 | 🟢 简单 | 🟢 简单 | 🟡 中等 |
二、环境准备与安装
1. 安装Aerich
# 基础安装
pip install aerich
# 如果使用特定数据库,安装对应驱动
pip install aerich[asyncpg] # PostgreSQL
pip install aerich[aiomysql] # MySQL2. 项目结构建议
test_platform/
├── app/
│ ├── __init__.py
│ ├── main.py # FastAPI主文件
│ ├── models/ # 数据模型
│ │ ├── __init__.py
│ │ ├── user.py
│ │ └── testcase.py
│ ├── config.py # 配置文件
│ └── routers/ # API路由
├── migrations/ # 迁移文件(自动生成)
├── aerich.ini # Aerich配置(自动生成)
├── pyproject.toml # 项目配置
└── requirements.txt # 依赖列表3. 配置文件设置
# config.py
TORTOISE_ORM = {
"connections": {
"default": {
"engine": "tortoise.backends.sqlite",
"credentials": {"file_path": "test_platform.db"}
}
},
"apps": {
"models": {
"models": ["app.models", "aerich.models"],
"default_connection": "default",
}
},
"use_tz": True,
"timezone": "Asia/Shanghai"
}三、Aerich初始化
1. 初始化Aerich
# 方法一:使用配置文件
aerich init -t config.TORTOISE_ORM
# 方法二:直接指定数据库URL
aerich init -t config.TORTOISE_ORM --location ./migrations执行后会生成:
aerich.ini配置文件migrations/目录
2. 查看生成的配置文件
# aerich.ini
[tool.aerich]
tortoise_orm = "config.TORTOISE_ORM"
location = "./migrations"
src_folder = "./."3. 初始化数据库
# 首次初始化数据库(创建表结构)
aerich init-db这个命令会:
- 根据当前模型创建数据库表
- 创建第一个迁移文件
- 在数据库中创建迁移历史表
四、基础迁移操作
1. 创建模型
# app/models/user.py
from tortoise.models import Model
from tortoise import fields
class User(Model):
"""用户模型"""
id = fields.IntField(pk=True)
username = fields.CharField(max_length=50, unique=True)
email = fields.CharField(max_length=100)
created_at = fields.DatetimeField(auto_now_add=True)
class Meta:
table = "users"
# app/models/testcase.py
class TestCase(Model):
"""测试用例模型"""
id = fields.IntField(pk=True)
name = fields.CharField(max_length=200)
description = fields.TextField(null=True)
author = fields.ForeignKeyField("models.User", related_name="testcases")
priority = fields.IntField(default=3)
created_at = fields.DatetimeField(auto_now_add=True)
class Meta:
table = "testcases"2. 生成迁移文件
# 检测模型变更并生成迁移文件
aerich migrate --name "add_user_and_testcase_models"
# 不指定名称(自动生成)
aerich migrate3. 查看迁移文件
# migrations/models/0_20241201120000_init.py
from tortoise import BaseDBAsyncClient
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
CREATE TABLE IF NOT EXISTS "users" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"username" VARCHAR(50) NOT NULL UNIQUE,
"email" VARCHAR(100) NOT NULL,
"created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS "testcases" (
"id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"name" VARCHAR(200) NOT NULL,
"description" TEXT,
"priority" INT NOT NULL DEFAULT 3,
"created_at" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"author_id" INT NOT NULL REFERENCES "users" ("id") ON DELETE CASCADE
);
"""
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
DROP TABLE IF EXISTS "testcases";
DROP TABLE IF EXISTS "users";
"""4. 应用迁移
# 应用所有未应用的迁移
aerich upgrade
# 查看迁移状态
aerich history
# 查看当前版本
aerich heads五、常见迁移场景
1. 添加字段
# 修改模型:给User添加is_active字段
class User(Model):
id = fields.IntField(pk=True)
username = fields.CharField(max_length=50, unique=True)
email = fields.CharField(max_length=100)
is_active = fields.BooleanField(default=True) # 新增字段
created_at = fields.DatetimeField(auto_now_add=True)
class Meta:
table = "users"# 生成迁移
aerich migrate --name "add_user_is_active_field"
# 应用迁移
aerich upgrade2. 修改字段
# 修改字段长度
class User(Model):
id = fields.IntField(pk=True)
username = fields.CharField(max_length=100, unique=True) # 从50改为100
email = fields.CharField(max_length=150) # 从100改为150
is_active = fields.BooleanField(default=True)
created_at = fields.DatetimeField(auto_now_add=True)
class Meta:
table = "users"3. 添加索引
class TestCase(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=200)
description = fields.TextField(null=True)
author = fields.ForeignKeyField("models.User", related_name="testcases")
priority = fields.IntField(default=3)
status = fields.CharField(max_length=20, default="active") # 新增字段
created_at = fields.DatetimeField(auto_now_add=True)
class Meta:
table = "testcases"
indexes = [
("status", "priority"), # 复合索引
("created_at",), # 单字段索引
]4. 删除字段
# 删除description字段
class TestCase(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=200)
# description字段被删除
author = fields.ForeignKeyField("models.User", related_name="testcases")
priority = fields.IntField(default=3)
status = fields.CharField(max_length=20, default="active")
created_at = fields.DatetimeField(auto_now_add=True)
class Meta:
table = "testcases"⚠️ 注意:删除字段是不可逆操作,在生产环境中要特别小心!
六、高级迁移操作
1. 回滚迁移
# 回滚到上一个版本
aerich downgrade
# 回滚到指定版本
aerich downgrade --version 1
# 查看可回滚的版本
aerich history2. 数据迁移
有时候我们不仅需要修改表结构,还需要迁移数据:
# migrations/models/2_20241201130000_migrate_user_data.py
from tortoise import BaseDBAsyncClient
async def upgrade(db: BaseDBAsyncClient) -> str:
# 结构变更
sql_schema = """
ALTER TABLE "users" ADD COLUMN "full_name" VARCHAR(100);
"""
# 数据迁移
sql_data = """
UPDATE "users" SET "full_name" = "username" WHERE "full_name" IS NULL;
"""
return sql_schema + sql_data
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "users" DROP COLUMN "full_name";
"""3. 自定义迁移
# 创建空的迁移文件
aerich migrate --name "custom_data_migration" --empty
# 手动编辑迁移文件
# migrations/models/3_20241201140000_custom_data_migration.py
from tortoise import BaseDBAsyncClient
async def upgrade(db: BaseDBAsyncClient) -> str:
"""自定义数据迁移"""
# 复杂的数据处理逻辑
return """
-- 创建临时表
CREATE TEMPORARY TABLE temp_user_stats AS
SELECT
author_id,
COUNT(*) as testcase_count,
AVG(priority) as avg_priority
FROM testcases
GROUP BY author_id;
-- 更新用户统计信息
UPDATE users
SET stats = (
SELECT json_object(
'testcase_count', testcase_count,
'avg_priority', avg_priority
)
FROM temp_user_stats
WHERE temp_user_stats.author_id = users.id
);
DROP TABLE temp_user_stats;
"""
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
UPDATE users SET stats = NULL;
"""七、生产环境最佳实践
1. 迁移前的准备工作
# 1. 备份数据库
pg_dump test_platform > backup_$(date +%Y%m%d_%H%M%S).sql
# 2. 检查迁移文件
aerich history
# 3. 在测试环境验证迁移
aerich upgrade --dry-run # 模拟执行(如果支持)2. 安全的迁移流程
# deploy_script.py
import asyncio
import subprocess
from tortoise import Tortoise
async def safe_migration():
"""安全的迁移流程"""
try:
# 1. 连接数据库检查状态
await Tortoise.init(config=TORTOISE_ORM)
print("✅ 数据库连接成功")
# 2. 检查当前迁移状态
result = subprocess.run(["aerich", "history"], capture_output=True, text=True)
print(f"📋 当前迁移状态:\n{result.stdout}")
# 3. 执行迁移
print("🚀 开始执行迁移...")
result = subprocess.run(["aerich", "upgrade"], capture_output=True, text=True)
if result.returncode == 0:
print("✅ 迁移执行成功")
print(result.stdout)
else:
print("❌ 迁移执行失败")
print(result.stderr)
return False
# 4. 验证迁移结果
print("🔍 验证迁移结果...")
# 这里可以添加数据完整性检查
return True
except Exception as e:
print(f"❌ 迁移过程出错: {e}")
return False
finally:
await Tortoise.close_connections()
if __name__ == "__main__":
success = asyncio.run(safe_migration())
exit(0 if success else 1)3. 回滚策略
#!/bin/bash
# rollback.sh - 回滚脚本
echo "⚠️ 准备回滚数据库迁移..."
# 检查当前版本
echo "📋 当前迁移状态:"
aerich history
# 确认回滚
read -p "确认要回滚到上一个版本吗? (y/N): " confirm
if [[ $confirm != [yY] ]]; then
echo "❌ 回滚已取消"
exit 1
fi
# 备份当前数据
echo "💾 备份当前数据..."
pg_dump test_platform > "rollback_backup_$(date +%Y%m%d_%H%M%S).sql"
# 执行回滚
echo "🔄 执行回滚..."
aerich downgrade
if [ $? -eq 0 ]; then
echo "✅ 回滚成功"
else
echo "❌ 回滚失败"
exit 1
fi
# 验证回滚结果
echo "🔍 验证回滚结果..."
aerich history八、与FastAPI集成
1. 启动时自动迁移
# app/main.py
from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise
import subprocess
import os
app = FastAPI(title="测试平台API")
@app.on_event("startup")
async def startup_event():
"""应用启动时的处理"""
# 开发环境自动迁移
if os.getenv("ENVIRONMENT") == "development":
print("🔄 开发环境:执行数据库迁移...")
try:
result = subprocess.run(
["aerich", "upgrade"],
capture_output=True,
text=True,
check=True
)
print("✅ 数据库迁移完成")
except subprocess.CalledProcessError as e:
print(f"❌ 数据库迁移失败: {e.stderr}")
raise
# 注册Tortoise-ORM
register_tortoise(
app,
config=TORTOISE_ORM,
generate_schemas=False, # 使用Aerich管理schema,不自动生成
add_exception_handlers=True,
)2. 健康检查接口
@app.get("/health/database")
async def database_health():
"""数据库健康检查"""
try:
from tortoise import connections
# 检查数据库连接
conn = connections.get("default")
await conn.execute_query("SELECT 1")
# 检查迁移状态
result = subprocess.run(
["aerich", "history"],
capture_output=True,
text=True
)
return {
"status": "healthy",
"database": "connected",
"migrations": "up_to_date" if "No migrations" not in result.stdout else "pending"
}
except Exception as e:
return {
"status": "unhealthy",
"error": str(e)
}九、常见问题与解决方案
1. 迁移冲突
# 问题:多人开发时迁移文件冲突
# 解决方案:
# 1. 拉取最新代码
git pull origin main
# 2. 重置迁移(谨慎使用)
rm -rf migrations/
aerich init -t config.TORTOISE_ORM
aerich init-db
# 3. 或者手动合并迁移文件
aerich migrate --name "merge_migrations"2. 生产环境迁移失败
# 问题:生产环境迁移失败,需要手动修复
# 解决方案:
async def manual_fix_migration():
"""手动修复迁移状态"""
from tortoise import connections
conn = connections.get("default")
# 查看迁移历史表
result = await conn.execute_query(
"SELECT * FROM aerich ORDER BY id DESC LIMIT 5"
)
print("最近的迁移记录:", result)
# 手动标记迁移为已完成(谨慎使用)
# await conn.execute_query(
# "INSERT INTO aerich (version, app, content) VALUES (?, ?, ?)",
# ["0002_auto_20241201_1400", "models", "manual_fix"]
# )3. 数据类型兼容性
# 问题:不同数据库的数据类型差异
# 解决方案:使用条件迁移
from tortoise import BaseDBAsyncClient
async def upgrade(db: BaseDBAsyncClient) -> str:
"""兼容不同数据库的迁移"""
# 获取数据库类型
db_type = db.__class__.__name__
if "sqlite" in db_type.lower():
return """
ALTER TABLE users ADD COLUMN metadata TEXT;
"""
elif "postgres" in db_type.lower():
return """
ALTER TABLE users ADD COLUMN metadata JSONB;
"""
elif "mysql" in db_type.lower():
return """
ALTER TABLE users ADD COLUMN metadata JSON;
"""
else:
raise ValueError(f"不支持的数据库类型: {db_type}")十、总结
Aerich作为Tortoise-ORM的迁移工具,为我们提供了:
✅ 版本控制 - 跟踪数据库结构的每一次变更 ✅ 团队协作 - 确保开发团队数据库结构一致 ✅ 安全部署 - 在生产环境中安全地应用变更 ✅ 回滚能力 - 出现问题时快速回滚 ✅ 自动化 - 与CI/CD流程无缝集成
最佳实践总结
- 始终备份:在生产环境执行迁移前备份数据库
- 测试验证:在测试环境充分验证迁移脚本
- 渐进式迁移:大的结构变更分解为多个小的迁移
- 监控迁移:监控迁移执行时间和资源使用
- 文档记录:为复杂迁移编写详细的文档说明
学习建议
- 从简单开始:先掌握基本的增删改字段操作
- 理解原理:了解迁移文件的结构和执行机制
- 实战练习:在开发项目中实际使用Aerich
- 关注安全:学习生产环境的安全迁移实践
🎯 实战提醒:数据库迁移是一项需要谨慎对待的操作,特别是在生产环境中。始终要有备份和回滚计划,确保数据安全!
Aerich让数据库迁移变得简单而安全,是构建现代Python Web应用不可缺少的工具。掌握它,你就掌握了数据库演进的主动权!
from tortoise import fields, models
class User(models.Model):
# 保留的字段
id = fields.IntField(pk=True)
username = fields.CharField(max_length=255, unique=True)
# 新增字段
phone = fields.CharField(max_length=20, null=True) # 新增电话字段
age = fields.IntField(null=True) # 新增年龄字段
# 删除的字段 (原email字段将被移除)
# email = fields.CharField(max_length=255) # 注释掉或删除这行2. 生成迁移文件
这将:
- 比较模型与当前数据库的差异
- 在
migrations/versions生成迁移脚本(如20230815_1234_add_phone_and_age_remove_email.py)
3. 检查生成的迁移文件
打开生成的迁移文件确认变更是否符合预期:
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "user" ADD "phone" VARCHAR(20) NULL;
ALTER TABLE "user" ADD "age" INT NULL;
ALTER TABLE "user" DROP COLUMN "email";
"""
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
ALTER TABLE "user" ADD "email" VARCHAR(255) NULL;
ALTER TABLE "user" DROP COLUMN "phone";
ALTER TABLE "user" DROP COLUMN "age";
"""4. 应用迁移
这将执行 upgrade() 中的 SQL 语句
5. 验证结果
aerich history # 查看迁移历史
aerich heads # 查看当前最新迁移二、数据保留情况分析
| 操作类型 | 数据是否保留 | 注意事项 |
|---|---|---|
| 新增字段 | ✅ 保留 | 新增的 nullable 字段初始为 NULL,非空字段需设置默认值 |
| 删除字段 | ❌ 该字段数据丢失 | 如需保留数据,应先备份再迁移 |
| 修改字段类型 | ⚠️ 可能丢失 | 类型不兼容时数据可能被截断或丢失 |
| 重命名字段 | ❌ 视为删除+新增 | 需要特殊处理才能保留数据 |
三、高级场景处理
1. 需要保留被删除字段的数据
解决方案:自定义迁移脚本
- 生成空迁移文件:
- 手动编辑迁移文件:
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
-- 1. 先添加新字段
ALTER TABLE "user" ADD "phone" VARCHAR(20) NULL;
-- 2. 将email数据复制到phone
UPDATE "user" SET "phone" = "email";
-- 3. 最后删除旧字段
ALTER TABLE "user" DROP COLUMN "email";
"""2. 修改非空字段
# 模型修改示例
address = fields.CharField(max_length=255, null=False) # 从nullable改为非空处理方案:
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
-- 1. 先设置默认值
UPDATE "user" SET "address" = '未知' WHERE "address" IS NULL;
-- 2. 修改字段为非空
ALTER TABLE "user" ALTER COLUMN "address" SET NOT NULL;
"""3. 重命名字段(保留数据)
# 模型修改示例
username = fields.CharField(max_length=255) # 原为name字段自定义迁移:
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
-- PostgreSQL语法
ALTER TABLE "user" RENAME COLUMN "name" TO "username";
-- SQLite语法(不支持直接重命名,需要创建新表)
/*
1. 创建临时表
2. 复制数据
3. 删除原表
4. 重命名临时表
*/
"""四、数据安全最佳实践
- 备份优先:
# SQLite示例
cp db.sqlite3 db.sqlite3.bak
# PostgreSQL示例
pg_dump -U username -d dbname > backup.sql- 测试环境验证:
- 先在测试数据库执行迁移
- 验证数据完整性和应用功能
- 分阶段部署:
- 先部署添加字段的迁移
- 后续迁移再移除字段
- 使用事务(数据库支持时):
async def upgrade(db: BaseDBAsyncClient) -> str:
async with db.in_transaction():
await db.execute_script('ALTER TABLE...')
await db.execute_script('UPDATE TABLE...')五、迁移失败恢复
如果迁移出错,可以回滚:
# 回滚到上一个版本
aerich downgrade -v -1
# 检查数据库状态
aerich heads然后修复迁移文件后重新尝试。
六、总结操作流程图
[修改模型] → [生成迁移] → [检查迁移脚本] → [备份数据库] → [应用迁移] → [验证数据]
↑ ↓
└──[发现错误] ← [测试失败]通过 Aerich 进行规范的数据库迁移,可以最大限度地保证数据安全,同时保持数据库结构与代码模型同步。关键是要理解每种模型变更对现有数据的影响,并在生产环境操作前做好充分测试和备份。
<font style="color:rgb(64, 64, 64);">aerich init -t tests.backends.mysql.TORTOISE_ORM</font>
这个命令是用于初始化 Aerich 迁移工具的配置,下面我将详细解释每个部分:
命令结构分解
| 部分 | 说明 |
|---|---|
aerich | Aerich 命令行工具 |
init | 初始化命令,用于设置迁移环境 |
-t或 --tortoise-orm | 指定 Tortoise-ORM 配置的导入路径 |
tests.backends.mysql.TORTOISE_ORM | Python 导入路径,指向包含 Tortoise-ORM 配置的变量 |
详细解释
1. 命令作用
这条命令会:
- 创建
migrations目录(如果不存在) - 生成
aerich.ini配置文件 - 记录指定的 Tortoise-ORM 配置路径
2. 参数说明
-t tests.backends.mysql.TORTOISE_ORM 表示:
- 使用位于
tests/backends/mysql.py文件中的TORTOISE_ORM变量作为数据库配置 - Aerich 将通过 Python 导入系统导入这个配置
3. 预期的文件结构
假设项目结构如下:
project/
├── tests/
│ ├── __init__.py
│ ├── backends/
│ │ ├── __init__.py
│ │ └── mysql.py # 包含 TORTOISE_ORM 配置
├── aerich.ini # 初始化后生成
└── migrations/ # 初始化后生成4. 配置文件示例
tests/backends/mysql.py 内容可能类似:
TORTOISE_ORM = {
"connections": {
"default": {
"engine": "tortoise.backends.mysql",
"credentials": {
"host": "localhost",
"port": 3306,
"user": "root",
"password": "password",
"database": "test",
}
}
},
"apps": {
"models": {
"models": ["app.models", "aerich.models"],
"default_connection": "default",
}
}
}执行后的变化
- 生成
aerich.ini文件,内容类似:
[aerich]
tortoise_orm = tests.backends.mysql.TORTOISE_ORM
location = ./migrations- 创建空
migrations目录
后续操作
初始化后通常需要:
# 初始化数据库(首次)
aerich init-db
# 生成迁移文件(模型变更后)
aerich migrate --name "add_user_table"
# 应用迁移
aerich upgrade注意事项
- Python 导入路径必须正确:
- 确保项目根目录在 Python 路径中
- 确保指定路径可以导入
- 配置验证:
- 执行前确认
TORTOISE_ORM配置正确 - 特别是数据库连接信息和模型路径
- 执行前确认
- 多环境配置:
- 可以为不同环境准备不同配置文件
- 如
tests.backends.mysql.TORTOISE_ORM和tests.backends.sqlite.TORTOISE_ORM
这个初始化命令是使用 Aerich 进行数据库迁移管理的第一步,确保正确设置后才能进行后续的迁移生成和应用操作。
import os # 用于操作文件路径和环境变量
import typing # 提供类型提示支持
from pydantic_settings import BaseSettings # Pydantic 的配置类基类
# 定义配置类 Settings,继承自 BaseSettings
class Settings(BaseSettings):
# 基础信息
VERSION: str = "0.1.0" # 项目版本号
APP_TITLE: str = "Testing AI" # 应用标题
PROJECT_NAME: str = "Testing AI" # 项目名称
APP_DESCRIPTION: str = "Description" # 应用描述
# CORS 配置(跨域资源共享)
CORS_ORIGINS: typing.List = ["*"] # 允许的跨域请求来源,默认允许所有来源
CORS_ALLOW_CREDENTIALS: bool = True # 是否允许携带凭证(如 Cookie)
CORS_ALLOW_METHODS: typing.List = ["*"] # 允许的 HTTP 方法,默认允许所有方法
CORS_ALLOW_HEADERS: typing.List = ["*"] # 允许的 HTTP 请求头,默认允许所有头
# 调试模式
DEBUG: bool = True # 调试模式开关,默认开启
# 目录路径
PROJECT_ROOT: str = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) # 项目的根目录
BASE_DIR: str = os.path.abspath(os.path.join(PROJECT_ROOT, os.pardir)) # 项目的基目录
LOGS_ROOT: str = os.path.join(BASE_DIR, "app/logs") # 日志文件存储路径
# JWT 配置
SECRET_KEY: str = "3488a63e1765035d386f05409663f55c83bfae3b3c61a932744b20ad14244dcf" # JWT 签名密钥(可通过 openssl rand -hex 32 生成)
JWT_ALGORITHM: str = "HS256" # JWT 签名算法
JWT_ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7 # JWT Token 的过期时间,默认为 7 天
# 数据库配置(使用 Tortoise ORM)
TORTOISE_ORM: dict = {
"connections": { # 数据库连接配置
"default": f"sqlite:///{os.path.join(BASE_DIR, 'db.sqlite3')}",
# SQLite 配置
# "sqlite": {
# "engine": "tortoise.backends.sqlite", # 使用 SQLite 引擎
# "credentials": {"file_path": f"{BASE_DIR}/db.sqlite3"}, # SQLite 数据库文件路径
# },
# MySQL/MariaDB 配置(示例,未启用)
# Install with: tortoise-orm[asyncmy]
# "mysql": {
# "engine": "tortoise.backends.mysql", # 使用 MySQL 引擎
# "credentials": {
# "host": "localhost", # 数据库主机地址
# "port": 3306, # 数据库端口
# "user": "yourusername", # 数据库用户名
# "password": "yourpassword", # 数据库密码
# "database": "yourdatabase", # 数据库名称
# },
# },
# PostgreSQL 配置(示例,未启用)
# Install with: tortoise-orm[asyncpg]
# "postgres": {
# "engine": "tortoise.backends.asyncpg", # 使用 PostgreSQL 引擎
# "credentials": {
# "host": "localhost", # 数据库主机地址
# "port": 5432, # 数据库端口
# "user": "yourusername", # 数据库用户名
# "password": "yourpassword", # 数据库密码
# "database": "yourdatabase", # 数据库名称
# },
# },
# MSSQL/Oracle 配置(示例,未启用)
# Install with: tortoise-orm[asyncodbc]
# "oracle": {
# "engine": "tortoise.backends.asyncodbc", # 使用 Oracle 引擎
# "credentials": {
# "host": "localhost", # 数据库主机地址
# "port": 1433, # 数据库端口
# "user": "yourusername", # 数据库用户名
# "password": "yourpassword", # 数据库密码
# "database": "yourdatabase", # 数据库名称
# },
# },
# SQLServer 配置(示例,未启用)
# Install with: tortoise-orm[asyncodbc]
# "sqlserver": {
# "engine": "tortoise.backends.asyncodbc", # 使用 SQLServer 引擎
# "credentials": {
# "host": "localhost", # 数据库主机地址
# "port": 1433, # 数据库端口
# "user": "yourusername", # 数据库用户名
# "password": "yourpassword", # 数据库密码
# "database": "yourdatabase", # 数据库名称
# },
# },
},
"apps": { # 定义应用及其对应的模型
"models": {
"models": ["app.models", "aerich.models"], # 包含的模型模块
"default_connection": "default", # 默认使用的数据库连接
},
},
"use_tz": False, # 是否使用时区感知的时间,默认关闭
"timezone": "Asia/Shanghai", # 时区设置,默认为上海时区
}
# 日期格式
DATETIME_FORMAT: str = "%Y-%m-%d %H:%M:%S" # 日期时间格式
# 实例化配置对象,加载所有配置
settings = Settings()
# 将 TORTOISE_ORM 配置直接暴露为模块级别的变量
TORTOISE_ORM = settings.TORTOISE_ORM修改 aerich init 命令以适应您的配置
根据您的配置文件 app/settings/config.py,您需要调整 aerich init 命令以正确指向您的 Tortoise-ORM 配置。
正确的初始化命令
详细解释
1. 命令结构解析
| 部分 | 说明 |
|---|---|
app.settings.config | 对应您的配置文件路径 app/settings/config.py |
settings | 您的配置文件中的 settings = Settings()实例 |
TORTOISE_ORM | Settings类中的 TORTOISE_ORM字典属性 |
2. 为什么这样修改?
您的配置结构与常规 Tortoise-ORM 配置不同:
- 配置嵌套在
Settings类中 - 最终配置通过
settings = Settings()实例化 - 因此需要完整路径
app.settings.config.settings.TORTOISE_ORM
3. 执行后的预期结果
- 生成
aerich.ini文件,内容类似:
[aerich]
tortoise_orm = app.settings.config.settings.TORTOISE_ORM
location = ./migrations- 创建空
migrations目录
完整操作流程
- 首先确保已安装 Aerich:
- 执行初始化命令:
- 初始化数据库(首次):
- 后续模型变更时:
# 生成迁移文件
aerich migrate --name "your_migration_name"
# 应用迁移
aerich upgrade注意事项
- Python 导入路径:
- 确保您的项目根目录在 Python 路径中
- 或者从项目根目录执行命令(推荐)
- 配置验证:
- 确认
settings.TORTOISE_ORM中的数据库连接信息正确 - 特别是
default_connection指定的连接已配置
- 确认
- 多环境支持:
如果您有不同环境的配置,可以:
# 开发环境
aerich init -t app.settings.config.settings.TORTOISE_ORM --env dev
# 生产环境
aerich init -t app.settings.config.prod_settings.settings.TORTOISE_ORM --env prod- SQLite 数据库文件:
根据您的配置,SQLite 数据库将创建在:
请确保该目录有写入权限
这样修改后,Aerich 就能正确识别和使用您的 Tortoise-ORM 配置进行数据库迁移管理了。
