tortoise-orm教程
简介
FastApi基于Starlette框架二次开发,使用pydantic做接口入参校验,可自动生成openapi形式的接口文档。
从Python3.6开始支持asyncio
之后,许多支持此特性的python web框架开始陆续出现,如sanic、fastapi,利用异步特性+异步ORM,可以提高web服务的并发和吞吐量。
Django3.0之后才开始支持Asgi协议,至当前最新版本3.0.7依旧未支持异步ORM。
不严谨的场景下性能测试结果是 FastAPI>Flask>Django3。
tortoise-orm
tortoise-orm是一个类Django的异步支持的ORM,如果之前使用过Django的话,语法基本一致,无需特殊学习。
最大的区别就是所有的ORM语句执行前都需要加入await
关键字,以此支持异步ORM读取操作。下面只简单介绍一些在使用过程中遇到的难点问题。
数据库连接
FastAPI的app主文件内, main.py:
from tortoise.contrib.fastapi import register_tortoise
register_tortoise(
app,
db_url=config.DATABASE_URI,
modules={"models": ["client.models"]},
generate_schemas=False,
add_exception_handlers=False,
)
其中app为FastAPI的app对象。
modules为你models文件定义的路径。
generate_schemas为True的话会自动检测相关的表是否存在,不存在的话会自动尝试创建,表中的字段变化的话,不会自动更新的。
add_exception_handlers为True的话会自动为你处理ORM的DoesNotExist异常。
时区问题
create_time = fields.DatetimeField(auto_now_add=True, description='创建时间')
update_time = fields.DatetimeField(auto_now=True, description='更新时间')
models在定义的时候,经常会定义创建时间和更新时间,这个时间在不显式指定时,会由ORM自动补全,当前tortoise-orm(版本tortoise-orm==0.16.16)好像不支持指定时区,入库使用的时间为UTC时间,源码为:
\tortoise\fields\data.py Line 304:
def to_db_value(
self, value: Optional[datetime.datetime], instance: "Union[Type[Model], Model]"
) -> Optional[datetime.datetime]:
# Only do this if it is a Model instance, not class. Test for guaranteed instance var
if hasattr(instance, "_saved_in_db") and (
self.auto_now
or (self.auto_now_add and getattr(instance, self.model_field_name) is None)
):
value = datetime.datetime.utcnow()
setattr(instance, self.model_field_name, value)
return value
return value
value强制指定为datetime.datetime.utcnow()
,当前直接重写自定义的字段解决,将datetime.datetime.utcnow()
修改为datetime.datetime.now()
即可。
日志问题
tortoise-orm所有的操作日志都会log在一个名为db_client的log对象下,该log默认不会输出至控制台,若想查看每次操作对应的SQL语句,可以为该log对象添加handler即可。
# 数据库日志
db_log = logging.getLogger("db_client")
db_log.setLevel(10)
handler = WatchedFileHandler(filename='log/db_client.log')
formatter = logging.Formatter('%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
handler.setFormatter(formatter)
db_log.addHandler(handler)
想要查看单次ORM执行时对应的sql语句,直接在ORM语句后调用下.sql()
方法即可。