fastapi之tortoise-orm

2023-11-03

概述

fastapi是一个很优秀的框架,但是缺少一个合适的orm,官方代码里面使用的是sqlalchemy,异步也是使用的这个。但是我这边看到有tortoise-orm这个异步orm框架,不知道效率如何,这里先学习,之后做一个性能测试比较一下。
整个框架非常接近django,如果我没写的地方,要么是和django差不多,要么是没这功能。

fastapi引入

在main.py文件里面引入如下代码:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from models import User_Pydantic, UserIn_Pydantic, Users
from tortoise.contrib.fastapi import HTTPNotFoundError, register_tortoise

app = FastAPI(title="Tortoise ORM FastAPI example")

...
register_tortoise(#这里是启动app的,之后会考虑和使用uvicorn启动的性能差别
    app,
    db_url="sqlite://:memory:",#数据库信息
    modules={"models": ["models"]},#models列表
    generate_schemas=True,#如果数据库为空,则自动生成对应表单,生产环境不要开
    add_exception_handlers=True,#生产环境不要开,会泄露调试信息
)

引入tortoise-orm的方法:register_tortoise

def register_tortoise(
    app: FastAPI,
    config: Optional[dict] = None,
    config_file: Optional[str] = None,
    db_url: Optional[str] = None,
    modules: Optional[Dict[str, List[str]]] = None,
    generate_schemas: bool = False,
    add_exception_handlers: bool = False,
) -> None:
    """
    在fastapi注册startup和shutdown

    使用 ``config``, ``config_file``或 ``(db_url, modules)``三者之一来配置
    示例
    ----------
    config:
        Dict containing config:
        Example
        -------
            {
                'connections': {
                    # Dict format for connection
                    'default': {
                        'engine': 'tortoise.backends.asyncpg',
                        'credentials': {
                            'host': 'localhost',
                            'port': '5432',
                            'user': 'tortoise',
                            'password': 'qwerty123',
                            'database': 'test',
                        }
                    },
                    # Using a DB_URL string
                    'default': 'postgres://postgres:qwerty123@localhost:5432/events'
                },
                'apps': {
                    'models': {
                        'models': ['__main__'],
                        # If no default_connection specified, defaults to 'default'
                        'default_connection': 'default',
                    }
                }
            }
    config_file:
        Path to .json or .yml (if PyYAML installed) file containing config with
        same format as above.
    db_url:
        Use a DB_URL string. See :ref:`db_url`
    modules:
        Dictionary of ``key``: [``list_of_modules``] that defined "apps" and modules that
        should be discovered for models.
    generate_schemas:
        True立即生成模式。仅适用于开发环境或SQLite ' ':memory: ' '数据库,生产环境数据库一定手动生成。
    add_exception_handlers:
        为' ' DoesNotExist ' ' & ' ' IntegrityError ' '添加一些自动异常处理程序。
不建议用于生产系统,因为它可能会泄漏数据。
    """
    pass

创建对应数据模型

tortoise-orm能使用的数据类型还挺丰富,满足了日常使用的需求。

创建Model

from tortoise import fields
from tortoise.models import Model
class User(Model):
	id=fields.IntField(pk=True)#主键必不可少

通过继承的方式创建Model

from tortoise import fields
from tortoise.models import Model

class TimestampMixin():
    created_at = fields.DatetimeField(null=True, auto_now_add=True)
    modified_at = fields.DatetimeField(null=True, auto_now=True)

class NameMixin():
    name = fields.CharField(40, unique=True)

class MyAbstractBaseModel(Model):
    id = fields.IntField(pk=True)
    class Meta:
        abstract = True
#注意数据库里面对应表顺序可能会比较乱。。
class UserModel(TimestampMixin, MyAbstractBaseModel):
    # 覆盖继承的字段
    id = fields.UUIDField(pk=True)
    # 新增一些字段
    first_name = fields.CharField(20, null=True)
    class Meta:
        table = "user"

class RoleModel(TimestampMixin, NameMixin, MyAbstractBaseModel):
    class Meta:
        table = "role"

设置数据库字段field

主要有如下字段(这些字段都没啥好说的,):

#常规字段
BigIntField,
BinaryField,
BooleanField,
CharEnumField,
CharField,
DateField,
DatetimeField,
DecimalField,
FloatField,
IntEnumField,#继承于SmallIntField
IntField,
JSONField,
SmallIntField,
TextField,
TimeDeltaField,
UUIDField,
#关系字段(relation不知道啥用,)
BackwardFKRelation,
BackwardOneToOneRelation,
ForeignKeyField,#外键
ForeignKeyNullableRelation,
ForeignKeyRelation,
ManyToManyField,#多对多
ManyToManyRelation,#反向代码提示的工具
OneToOneField,#一对一
OneToOneNullableRelation,
OneToOneRelation,
ReverseRelation,

关系键讲解:
ForeignKeyField:

tournament = fields.ForeignKeyField('models.Tournament', related_name='events')#related_name关键字参数,用于为引用的模型定义查询自己的字段,默认为名字+set
participants = fields.ManyToManyField('models.Team', related_name='events')
modified = fields.DatetimeField(auto_now=True)
prize = fields.DecimalField(max_digits=10, decimal_places=2, null=True)

反向代码提示
在使用外键的时候,我们需要获取到反向代码提示(即被绑定的model查询绑定model),这个时候需要使用relation字段来提示,(其实你不加也没啥关系,只是个提示作用,在django里面是编辑器和插件提前内置了相关字段所以不用手写
示例代码如下:

from tortoise.models import Model
from tortoise import fields

class Tournament(Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=255)
    events: fields.ReverseRelation["Event"]#仅用于代码提示,注意events必须和Event里面的外键指定的related_name同名

class Event(Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=255)
    tournament: fields.ForeignKeyRelation[Tournament] = fields.ForeignKeyField(
        "models.Tournament", related_name="events"
    )
    participants: fields.ManyToManyRelation["Team"] = fields.ManyToManyField(
        "models.Team", related_name="events", through="event_team"
    )#注意多对多,两个model里面都要写,虽然复杂了点,但是有代码提示还是很合算的。。through在django里面是指定多对多表的名字和功能,需要手动创建,这里可能是示例代码不全吧。。得测试

class Team(Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=255)
    events: fields.ManyToManyRelation[Event]#反向关系,

字段介绍

基本字段:
source_field :自定义数据库对应字段名称
generated :是否映射到数据库,
pk 是否为主键
null
default 可以为值或可调用对象
unique
index
description 描述功能,数据库注释用

自定义字段

tortoise-orm支持自定义字段,这个功能挺好用的,这里先不讲了,一般用不到。。。请自行查看:link.
可以通过继承,然后重构相关字段控制字段在数据库的存储方式

设置Meta

from tortoise import fields
from tortoise.models import Model
class User(Model):
	id=fields.IntField(pk=True)#主键必不可少
	class Meta:
		abstract=True#抽象模型,用于继承
		table="xxx"#该模型对应的表名称
		unique_together=(("field_a", "field_b"), )#设置唯一索引,参考django
		table_description = ""#数据库对该表的注释
		indexes=(("field_a", "field_b"), )#指定列集为非唯一索引,类似django在字段上的index
		ordering = ["name", "-score"]#设置默认查询结果的顺序

Model模型方法

#常用查询方法我就不提了,讲一些不常用的
annotate()#使用额外的函数/聚合对结果进行再过滤,,
bulk_create()#批量插入:

User.bulk_create([
    User(name="...", email="..."),
    User(name="...", email="...")
])

check()#检查model数据是否正确
describe()#序列化model,返回json
exists()#True/False 记录是否存在筛选器参数模式的model
register_listener()#侦听器,参数为信号,注意,更新到最新版才有。。数据的保存和删除前后可以被监听,挺有用的一个东西,使用说明查看链接:https://tortoise-orm.readthedocs.io/en/latest/examples/basic.html#model-signals
update_from_dict()#通过dict更新数据,配合schema很有用,主要用于字段更新,schema.dict有一个只获取填写结果字段的方法,配合这个可以实现局部更新

查询

参考django,略。

Q对象查询

这一块主要针对复杂查询。
有时,您需要执行比简单 AND 提供的更复杂的查询。幸运的是,我们有Q对象来调味的东西,并帮助您找到你需要的。然后,这些 Q 对象可用作参数。.filter().filter()

Q 对象用途极多,例如用例:
创建 OR 筛选器
嵌套筛选器
倒置过滤器
例如,查找名称或 的事件:Event 1Event 2

found_events = await Event.filter(
    Q(name='Event 1') | Q(name='Event 2')
)
#等效于:
	found_events = await Event.filter(
    Q(Q(name='Event 1'), Q(name='Event 2'), join_type="OR")#如果省略join_type,则为AND
)

字段过滤

在搜索的时候增加后缀可以实现字段的过滤效果:
比如:

teams = await Team.filter(name__icontains='CON')

相关参数如下:

  • not
  • in- 检查字段的值是否位于传递列表中
  • not_in
  • gte- 大于或等于传递的值
  • gt- 大于传递的值
  • lte- 低于或等于传递的值
  • lt- 低于传递值
  • range- 介于和给定两个值之间
  • isnull- 字段为空
  • not_isnull- 字段不为空
  • contains- 字段包含指定的子字符串
  • icontains- 不区分大小写contains
  • startswith- 如果字段以值开头
  • istartswith- 不区分大小写startswith
  • endswith- 如果字段以值结尾
  • iendswith- 不区分大小写endswith
  • iequals- 区分大小写等于

预取

通过预取,可以减少数据库读取次数,然后提高响应速度
有时只需要获取某些相关记录。您可以使用对象实现:Prefetch
示例:

tournament_with_filtered = await Tournament.all().prefetch_related(
    Prefetch('events', queryset=Event.filter(name='First'))
).first()

更多的参考:预取详情

F表达式

某些时候,我们只是需要将数据进行一次计算或处理然后保存,我们并不在意值是多少,只是想把值进行我们指定的修改,就可以使用F表达式,这样就可以减少一次数据库读取(我感觉好像没卵用啊。。。)
参考如下:

from tortoise.expressions import F
await User.filter(id=1).update(balance = F('balance') - 10)
await User.filter(id=1).update(balance = F('balance') + F('award'), award = 0)

# or use .save()
user = await User.get(id=1)
user.balance = F('balance') - 10
await user.save(update_fields=['balance'])

功能和聚合


请参考功能和聚合

事务

略 请参考事务

根据Model生成Schema

讲道理schema这个东西名字挺奇葩的。。。不过既然官网这么弄就这么弄吧。这个可以很方便的生成相关字段
注意,schema不要有相同的类名,会报错的

User_Pydantic = pydantic_model_creator(Users, name="User")
UserIn_Pydantic = pydantic_model_creator(Users, name="UserIn", exclude_readonly=True)

下面这个文档里面还没讲解;
可以通过在model里面创建一个class PydanticMeta来实现创建schema的控制:

class PydanticMeta:
    """
    The ``PydanticMeta`` class is used to configure metadata for generating the pydantic Model.

    Usage:

    .. code-block:: python3

        class Foo(Model):
            ...

            class PydanticMeta:
                exclude = ("foo", "baa")
                computed = ("count_peanuts", )
    """

    #: If not empty, only fields this property contains will be in the pydantic model
    include: Tuple[str, ...] = ()

    #: Fields listed in this property will be excluded from pydantic model
    exclude: Tuple[str, ...] = ()

    #: Computed fields can be listed here to use in pydantic model
    computed: Tuple[str, ...] = ()

    #: Use backward relations without annotations - not recommended, it can be huge data
    #: without control
    backward_relations: bool = True

    #: Maximum recursion level allowed
    max_recursion: int = 3

    #: Allow cycles in recursion - This can result in HUGE data - Be careful!
    #: Please use this with ``exclude``/``include`` and sane ``max_recursion``
    allow_cycles: bool = False

    #: If we should exclude raw fields (the ones have _id suffixes) of relations
    exclude_raw_fields: bool = True

    #: Sort fields alphabetically.
    #: If not set (or ``False``) then leave fields in declaration order
    sort_alphabetically: bool = False

如果你想跨表搜索或join搜索,在computed里面定义。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

fastapi之tortoise-orm 的相关文章

随机推荐

  • 2023最新信息安全专业毕设题目推荐汇总

    0 简介 毕业季马上就要开始了 不少同学询问学长网安专业选题以及开题相关的问题 今天跟大家分享信息安全毕设选题 最新的信息安全 网络安全 专业毕设选题 难度适中 适合作为毕业设计 大家参考 学长整理的题目标准 相对容易 工作量达标 题目新颖
  • vue中调取支付宝支付接口,后台返回form表单前端处理

    前言 在项目中 支付功能是一个常见的功能 调用支付宝时 后段给我们的是一个form的富文本内容 分享下使用方法 方法 this api abc then res gt res data data默认是我们拿到的form代码 const di
  • AD设置板框内布线禁止区

    这个功能还可用于整体板框扩大 缩小
  • qwt6.0.0交叉编译,在mini2440完美运行

    qwt6 0 0交叉编译 在mini2440完美运行 QWT简介 QWT 全称是Qt Widgets for Technical Applications 是一个基于LGPL版权协议的开源项目 可生成各种统计图 它为具有技术专业背景的程序提
  • Python3 获取本机所有IP地址

    版权声明 更多最新原创文章请访问 最新原创主页 更多最全原创文章请访问 更多原创主页 先上代码 coding utf 8 Time 2018 2 10 18 24 Author 蛇崽 Email 643435675 QQ com File
  • vue2下npm安装国际化i18n包报错

    如题 我项目是vue2 在terminal控制台输入以下指令安装时报错 npm install vue i18n save 原因 在vue2环境下 默认安装 npm install vue i18n 的版本是 vue i18n 9 2 2
  • 【OpenCV图像处理】1.22 像素值映射

    相关理论 什么是像素重映射 简单点说就是把输入图像中各个像素按照一定的规则映射到另外一张图像的对应位置上去 形成一张新的图像 g x y
  • 电子商务计算机考试,电子商务师考试电子商务训练试题

    电子商务师考试电子商务训练试题 导语 电子商务师是指利用计算机技术 网络技术 通过专业的网络商务平台等现代信息技术 帮助商家与顾客或商家与商家之间从事各类商务活动或相关工作的人员 跟着小编一起来看看相关试题吧 1 确定事物之间异同的形式逻辑
  • Ingress配置跨域(服务包含websocket)

    nginx ingress默认是支持websocket 不需要添加配置 如果websocket的端口与当前服务不一致 则需要在rules中配置对应的路径 具体本文不体现 跨域主要配置有 nginx ingress kubernetes io
  • 【Java】maven-shaded-plugin超详细详解

    一 总体介绍 maven shaded plugin提供了两大基本功能 将依赖的jar包打包到当前jar包 常规打包是不会将所依赖的jar包打进来的 对依赖的jar包进行重命名 用于类的隔离 创建一个Shaded JAR maven sha
  • Opencv 入门(三)

    文章目录 图像梯度 Sobel算子 Scharr 算子 Laplacian算子 Canny边缘检测 图像金字塔 高斯金字塔 拉普拉斯金字塔 轮廓检测 画图函数 轮廓特征 面积 周长 轮廓近似 多边形 边界矩形 外接圆 图像梯度 Sobel算
  • 来做一个麦克纳姆轮吧!!

    想玩全向小车么 想搭建一个移动底盘么 想满足中二病的创造欲么 想 那么为什么不自己做一个麦克纳姆轮呢 自己动手丰衣足食 0 准备材料 3D打印机一台 打印耗材 直径2mm 长度60mm的铁轴 这种玩具模型里用的小铁轴刚好可以用来当麦克纳姆轮
  • 03-雾化

    const fog new THREE Fog color near far color 颜色 用于设置雾的颜色 以十六进制表示 near 近平面 处于这个距离之内的物体将被完全雾化 far 远平面 处于这个距离之外的物体将不受雾化影响
  • Java枚举类常量写法

    在写代码的过程中我们常常需要定义一些常量 以下代码是使用枚举类型定义常量的实例 有需要大家可以进行参考 public class MyConstant public enum StatusEnum CREATED 0 状态0 ASSIGNE
  • python趣味编程-盒子追逐者游戏

    在上一期我们用Python实现了一个奥赛罗游戏的游戏 这一期我们继续使用Python实现一个简单的盒子追逐追逐者游戏 让我们开始今天的旅程吧 在Python自由源代码中使用Turtle的盒子追逐者游戏 在Python中使用Turtle的盒子
  • 我使用Java one longin组件进行ADFS连接,但是logout endpoint有问题

    很抱歉 看起来你遇到了使用 Java OneLogin 组件连接 ADFS 时的注销端点问题 这可能是由于 ADFS 设置不正确或 Java OneLogin 组件的配置问题造成的 建议您检查相关文档 并确保 ADFS 和 Java One
  • 龙书(附录A):一个完整的编译器前端(学习记录)

    龙书 完整的编译器前端下载地址 ps 我设置的不要下载积分 如果还是不能下载的话请评论区留言 https download csdn net download Zheng lan 16779204 百度网盘下载 链接 https pan b
  • java8之Stream-Collect操作

    文章目录 collect Collector in Action 收集器 Collectors 常用规约操作 规约到一个单独的值 把数据装进一个list中 将数据收集到一个Set中 把数据收集到一个Map中 Using other coll
  • 《人工智能》之《非经典推理》习题解析

    教材 人工智能及其应用 蔡自兴等 2016m清华大学出版社 第5版 参考书 对应同系列博客 人工智能 之 非经典推理 人工智能 之 非经典推理 习题解析 1 非经典逻辑 非经典推理与经典逻辑 经典推理有何不同 2 什么是不确定性推理 为什么
  • fastapi之tortoise-orm

    目录 概述 fastapi引入 创建对应数据模型 创建Model 设置数据库字段field 字段介绍 自定义字段 设置Meta Model模型方法 查询 Q对象查询 字段过滤 预取 F表达式 功能和聚合 事务 根据Model生成Schema