aerich迁移tortoise-orm数据库教程
目录
1.介绍
tortoise-orm是异步orm,语法类似django-orm,非常简单方便;一般配合fastapi使用。
tortoise-orm自身有generate_schemas函数用于数据库表创建
但实际项目开发中使用较少,多用aerich来迁移model->数据库表
2.问题
aerich 0.8.0和0.8.1 版本 cmd执行命令 存在问题,aerich init-db upgrade等命令执行后 无法退出。
原因:0.7.2以上版本,默认一直连接数据库(config里面有数据库连接路径),命令端无法退出连接,因此在代码程序中采用aerich Command执行命令,需要lifespan中Tortoise.close_connections
https://fastapi.tiangolo.com/zh/advanced/events/?h=lifespan#lifespan
aerich 0.7.2版本 没有问题
3.tortoise-orm 自身函数迁移数据库
建议看官网代码(点击查看),直接上代码,必须2个py文件(model单独1个py文件,main 1个文件),这样才不会报错
Tortoise.init(db_url="sqlite://db.sqlite3", modules={"models": ["test"]})中 `models`可以改成任意名字,然后model表中外键、多对多需要改成对应名字.表名【models改成model,那么models.Clas需要改成model.Clas】,test为model表py模块(既可以是py文件也可是文件夹)
# test.py
from tortoise import fields, models, Tortoise
from enum import IntEnum
class AbstractModel(models.Model):
id = fields.UUIDField(primary_key=True, unique=True, db_index=True)
createdAt = fields.DatetimeField(auto_now_add=True, null=True)
updatedAt = fields.DatetimeField(auto_now=True, null=True)
class Meta:
abstract = True
class Gender(IntEnum):
MAN = 0
WOMAN = 1
class Student(AbstractModel):
name = fields.CharField(max_length=100, db_index=True, description="姓名")
gender = fields.IntEnumField(Gender, description="性别")
age = fields.IntField(description="年龄")
clas = fields.ForeignKeyField("models.Clas", related_name="students", description="班级外键")
class Clas(AbstractModel):
name = fields.CharField(max_length=200, db_index=True, description="班级名称")
# main.py
from tortoise import Tortoise, run_async
from test import Student, Clas
async def run():
await Tortoise.init(db_url="sqlite://db.sqlite3", modules={"models": ["test"]})
await Tortoise.generate_schemas()
clas1 = await Clas.create(name="一年级一班1")
stu = await Student.create(name="gyl", gender=1, age=30, clas=clas1)
print(await Student.all().values())
s = await Student.first().values()
print(s['id'])
print(s.keys())
if __name__=="__main__":
run_async(run())
4.aerich命令迁移tortoise-orm数据库表
使用版本为0.7.2,参考aerich官网(点击查看)命令,对于TORTOISE_ORM参数官网(点击查看)
aerich命令
aerich init -t config.TORTOISE_ORM 一般执行1次
aerich init-db 一般执行1次
aerich migrate 修改表就执行
aerich upgrade (aerich downgrade)
TORTOISE_ORM配置参数
# 一般需要将 connections中的key 改成default 对应default_connection
'''
注意:TORTOISE_ORM中
"apps": {
"modelApp": {
"models": ["models", "aerich.models"], # models里面有__init__.py就不需要再.了
"default_connection": "default" # 对应connections里面的
}
},
`modelApp`(key) 是定义表外键、多对多时 “{app}.{table_name}”中的app, 若modelApp重命名, 则外键里面的app也改成对应的名字 clas = fields.ForeignKeyField("modelApp.Clas", related_name="students")
`[]`里面的`models`是指的py模块路径(相对路径) 对于多级嵌套的的models文件夹 建议设置添加__init__.py导入所有表, 外键等就可以 modelApp."表名" 然后初始化创建表时 自动跟踪模块下面的所有table
'''
TORTOISE_ORM: dict = {
"connections": {
# SQLite configuration
# "sqlite": {
# "engine": "tortoise.backends.sqlite",
# "credentials": {"file_path": f"{具体路径}/db.sqlite3"}, # Path to SQLite database file
# },
# MySQL/MariaDB configuration
# Install with: tortoise-orm[asyncmy]
# "mysql": {
# "engine": "tortoise.backends.mysql",
# "credentials": {
# "host": "localhost", # Database host address
# "port": 3306, # Database port
# "user": "yourusername", # Database username
# "password": "yourpassword", # Database password
# "database": "yourdatabase", # Database name
# },
# },
# PostgreSQL configuration
# Install with: tortoise-orm[asyncpg]
# "postgres": {
# "engine": "tortoise.backends.asyncpg",
# "credentials": {
# "host": "localhost", # Database host address
# "port": 5432, # Database port
# "user": "yourusername", # Database username
# "password": "yourpassword", # Database password
# "database": "yourdatabase", # Database name
# },
# },
# MSSQL/Oracle configuration
# Install with: tortoise-orm[asyncodbc]
# "oracle": {
# "engine": "tortoise.backends.asyncodbc",
# "credentials": {
# "host": "localhost", # Database host address
# "port": 1433, # Database port
# "user": "yourusername", # Database username
# "password": "yourpassword", # Database password
# "database": "yourdatabase", # Database name
# },
# },
# SQLServer configuration
# Install with: tortoise-orm[asyncodbc]
# "sqlserver": {
# "engine": "tortoise.backends.asyncodbc",
# "credentials": {
# "host": "localhost", # Database host address
# "port": 1433, # Database port
# "user": "yourusername", # Database username
# "password": "yourpassword", # Database password
# "database": "yourdatabase", # Database name
# },
# },
},
'apps': {
'models': {
'models': ['models', 'aerich.models'], # []中的models为 表 模块(models.py或者models文件夹模块 需要有__init__.py导入表)
# If no default_connection specified, defaults to 'default'
'default_connection': 'default',
}
}
}
5.aerich代码迁移tortoise-orm数据库表
版本使用0.8.1
代码迁移,确保tortoise关闭连接,这样就不会出现代码执行后 无法退出的现象
from aerich import Command
from config import settings
from tortoise import Tortoise
async def init_db():
# settings.TORTOISE_ORM参考第4节
command = Command(tortoise_config=settings.TORTOISE_ORM)
# try:
# await command.init_db(safe=True)
# except FileExistsError:
# pass
await command.init() # 对应aerich init -t
try:
await command.init_db(safe=True) # 对应aerich init-db
except FileExistsError:
pass
try:
await command.migrate() # 对应aerich migrate
except AttributeError:
pass
await command.upgrade(run_in_transaction=True) # 对应aerich upgrade
async def lifespan():
await init_db()
await Tortoise.close_connections() # 执行完成后 关闭Tortoise连接,即关闭数据库连接,像sqlite shm wal文件才会消失,不可直接删除,否则数据库没有数据
import asyncio
asyncio.run(lifespan())
6. 注意事项(总结)
[1] 若采用aerich cmd端命令执行数据库创建、迁移,那么代码中推荐采用from tortoise.contrib.fastapi import register_tortoise,register_tortoise中generate_schemas调用的tortoise本身的函数迁移(不推荐生产使用,没有迁移记录);
[2] 若采用aerich Command 代码程序,那么需要Fastapi中的lifespan,执行关闭数据库连接;
[3] 目前个人采用[1]的aerich cmd命令端执行迁移,然后register_tortoise注册;[1]和[2]不要同时使用,后面可使用[2]