1.Tortoise ORM
- Tortoise ORM是一个易于使用的ORM(Object Relational Mapper),灵感来自Django,不多做介绍
2.模型定义
from tortoise import fields
from tortoise.models import Model
class DateTimeModel(Model):
created_at = fields.DatetimeField(auto_now_add=True, description="创建时间")
updated_at = fields.DatetimeField(auto_now=True, null=True, description="更新时间")
class Meta:
abstract = True
class GroupModel(DateTimeModel):
uuid = fields.UUIDField(source_field="uuid", pk=True, unique=True, description="用户组唯一标识")
name = fields.CharField(source_field="username", max_length=64, description="用户组名称")
parent_uuid = fields.CharField(source_field="parent_uuid", max_length=32, null=True)
users: fields.ReverseRelation["UserModel"]
class Meta:
table = "group"
class UserModel(DateTimeModel):
uuid = fields.UUIDField(source_field="uuid", pk=True, unique=True, description="用户唯一标识")
name = fields.CharField(source_field="username", max_length=64, description="用户展示名称,可以修改")
password = fields.CharField(source_field="password", max_length=128, description="用户密码")
status = fields.CharEnumField(UserStatus, default=UserStatus.OFFLINE, description="用户登录状态")
# 一对多,关联管系,和Django没什大的区别
group_uuid: fields.ForeignKeyRelation["GroupModel"] = \
fields.ForeignKeyField("models.GroupModel", related_name="group", on_delete=fields.CASCADE)
class Meta:
table = "user"
ordering = ["created_at"]
class PydanticMeta:
# 该字段不做展示,过滤作用
exclude = ["password"]
3.数据库配置
from typing import Type
from tortoise import Model
class Router:
@staticmethod
def db_for_read(model: Type[Model]):
return "slave"
@staticmethod
def db_for_write(model: Type[Model]):
return "master"
import urllib.parse
urllib.parse.quote_plus("kx%jj5/g")
TORTOISE_ORM = {
'connections': {
'master': {
# 'engine': 'tortoise.backends.asyncpg', PostgreSQL
'engine': 'tortoise.backends.mysql', # MySQL or Mariadb
'credentials': {
'host': '127.0.0.1',
'port': '3306',
'user': 'root',
'password': 'password',
'database': 'base',
'minsize': 1,
'maxsize': 5,
'charset': 'utf8mb4',
'echo': True
}
},
'slave': {
'engine': 'tortoise.backends.mysql',
'credentials': {
'host': '127.0.0.1',
'port': '3306',
'user': 'root',
'password': 'password',
'database': 'base',
'minsize': 1,
'maxsize': 5,
'charset': 'utf8mb4',
'echo': True
}
},
},
'apps': {
'models': {
'models': ['models', "aerich.models"],
'default_connection': 'master',
}
},
'routers': ["Router"],
'use_tz': False,
'timezone': 'Asia/Shanghai'
}
4.fastapi中引入
import uvicorn
from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise
app = FastAPI()
# 该方法会在fastapi启动时触发,内部通过传递进去的app对象,监听服务启动和终止事件
# 当检测到启动事件时,会初始化Tortoise对象,如果generate_schemas为True则还会进行数据库迁移
# 当检测到终止事件时,会关闭连接
register_tortoise(
app,
config=TORTOISE_ORM,
# generate_schemas=True, # 如果数据库为空,则自动生成对应表单,生产环境不要开
# add_exception_handlers=True, # 生产环境不要开,会泄露调试信息
)
if __name__ == '__main__':
uvicorn.run('main:app', host='0.0.0.0', port=8000, reload=True,
debug=True, workers=1)
5.通过aerich
这个模块实现数据库的迁移,类似于django的makemigrations
和migrate
功能
1.初始化配置,只需要使用一次
aerich init -t TORTOISE_ORM # 根据自己文件实际路径写
- 初始化完会在当前目录生成一个文件
pyproject.toml
和一个空文件夹migrations
pyproject.toml
:保存配置文件路径,低版本可能是aerich.ini
migrations
:存放迁移文件
2.初始化数据库,一般情况下只用一次
aerich init-db
- 如果
TORTOISE_ORM
配置文件中的models
改了名,则执行这条命令时需要增加--app
参数,来指定你修改的名字
- 生成migrstions/models文件夹
- 生成migrstions/models/0_xxxx_init.py文件夹
3.更新模型并进行迁移
aerich migrate --name drop_column
- 迁移文件名的格式为 {version_num}{datetime}.json。
1_202029051520102929_drop_column.json
如果aerich猜到您正在重命名列,它会要求重命名{old_column}为{new_column} [True],您可以选择True重命名列而不删除列,或者选择False删除列然后创建,如果使用MySQL,只有MySQL8.0+支持重命名。到语法
4.升级到最新版本
aerich upgrade
5.降级到指定版本
aerich downgrade # 默认回退一级
-v
:指定版本
-d
:降级的同时删除迁移文件
--yes
:确认删除,不再交互式输入
6.显示当前可以迁移的版本
aerich heads
7.显示迁移历史
aerich history