Tortoise ORM

官方文档:Tortoise ORM - Tortoise ORM v0.22.0 Documentation

简介

  • Tortoise ORM:异步,API和Django ORM 大多类似集成Pydantic;多用于asgi starlette / sanic / FastAPI...
  • Sqlalchemy:支持异步,Flask / Bottle/FastAPI ,集成Pydantic方案 可搜索SQLModel

表数据

CREATE TABLE `a` (
    `id` INT(10) NOT NULL AUTO_INCREMENT,
    `data` VARCHAR(500) NOT NULL DEFAULT '0' COLLATE 'utf8mb4_general_ci',
    `create_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`) USING BTREE
)
COLLATE='utf8mb4_general_ci'
ENGINE=InnoDB
;

INSERT INTO `a` (`id`, `data`, `create_date`) VALUES
    (1, '23', '2024-11-23 19:58:15'),
    (2, '24', '2024-11-23 19:58:20');

SQLAlchemy + FastAPI

"""
Tortoise ORM & SQLAlchemy
"""# SQlAlchemy
from sqlalchemy import Column, Integer, String, DateTime, func, select
from sqlalchemy.orm import declarative_baseBase = declarative_base()class SqlAlchemyTable(Base):__tablename__ = "a"id = Column(Integer, primary_key=True)data = Column(String)create_date = Column(DateTime, server_default=func.now())from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmakerengine = create_async_engine("sqlite+aiosqlite:///basic.sqlite3")
async_session = sessionmaker(engine, expire_on_commit=True, class_=AsyncSession
)def get_db():session = async_session()try:yield sessionfinally:session.close()from fastapi import FastAPI, Depends
from pydantic import BaseModelclass Response(BaseModel):id: intdata: strapp = FastAPI(title="SQLAlchemy")@app.get("/", response_model=Response)
async def index():# 视图里面实例db对象async with async_session() as session:result = await session.execute(select(SqlAlchemyTable).order_by(SqlAlchemyTable.id))return result.scalars().first().__dict__ # 第一条@app.get("/index")
async def index1(db: AsyncSession = Depends(get_db)):result = await db.execute(select(SqlAlchemyTable).order_by(SqlAlchemyTable.id))return result.scalars().all()if __name__ == '__main__':import uvicornuvicorn.run("__main__:app", reload=True)

Tortoise ORM + FastAPI

from tortoise import models, fields
from tortoise.contrib.fastapi import register_tortoise
from tortoise.contrib.pydantic import pydantic_model_creatorclass TortoiseOrm(models.Model):data = fields.CharField(max_length=30)create_date = fields.DatetimeField(auto_now_add=True, null=True)class Meta:table = 'a'Response = pydantic_model_creator(TortoiseOrm, name="OutPut", exclude=("create_date",))from fastapi import FastAPI
app = FastAPI(title="SQLAlchemy & TortoiseORM")register_tortoise(app,db_url="sqlite://basic.sqlite3",modules={"models": ["__main__"]},add_exception_handlers=True,
)@app.get("/", response_model=Response)
async def index():return await TortoiseOrm.all().order_by("id").first()@app.get("/index")
async def index1():return await TortoiseOrm.all().order_by("id")if __name__ == '__main__':import uvicornuvicorn.run("__main__:app", reload=True)

以上是两种orm操作数据库,个人选择了fastapi + tortoise-orm

1、创建模型&基础字段

- ORM

对象关系映射(英语:Object Relational Mapping),表 -> 类; 列 -> 属性

- Tortoise ORM

Tortoise ORM - Tortoise ORM v0.22.0 Documentation

Tortoise ORM 是一个受 Django 启发的易于使用的异步 ORM (对象关系映射器)。

pip install tortoise-orm -i https://pypi.douban.com/simple/

- 此篇文章参考:

https://tortoise.github.io/models.html

Fields - Tortoise ORM v0.22.0 Documentation

表定义

# -*- coding = utf-8 -*-
# @Time : 2024/11/23 20:03
# @Author: Frank
# @File: main.py
# @Software: PyCharm
from enum import IntEnum
from tortoise import models
from tortoise import fieldsclass AbstractModel(models.Model):# 主键,当表里所有属性都没设置pk时,默认生成一个IntField类型 id 的主键id = fields.UUIDField(pk=True)class Meta:# 抽象模型,不生成表abstract = Trueclass MixinTimeFiled:# 添加数据时间created = fields.DatetimeField(null=True, auto_now_add=True)# 修改数据时间modified = fields.DatetimeField(null=True, auto_now=True)class Gender(IntEnum):MAN = 0WOMAN = 1class UserModel(AbstractModel, MixinTimeFiled):# unique 是否唯一 max—length 数据长度 index 是否索引username = fields.CharField(max_length=20, description="描述", unique=True, index=True, source_field="user_name")# null 是否可以为空nickname = fields.CharField(max_length=30, description='nickname', null=True, default='777')# description 字段备注 ddl展示, 此处入库的为 0 or 1gender = fields.IntEnumField(Gender, description='sex', default=Gender.WOMAN)# max——digits 小输点左边最大位数,decimal——places 小数点右边最大位数balance = fields.DecimalField(max_digits=2, decimal_places=2, description='balance')is_admin = fields.BooleanField(default=False)job_info = fields.JSONField(default=dict)class Meta:# 自定义表名,不配置按照类名小写生成table = "test1"table_description = "set table ddl desc"# 多列设置唯一复合所有unique_together = (('gender', 'balance'),)# 排序ordering = ('is_admin',)# 索引indexes = ('balance',)async def init():# Here we create a SQLite DB using file "db.sqlite3"#  also specify the app name of "models"#  which contain models from "app.models"await Tortoise.init(# 数据库连接# db_url='sqlite://db.sqlite3',# 连接mysql pip install aiomysqldb_url='mysql://root:123456@127.0.0.1:3307/python',# 指定管理的models,__main__ 🈯️当前文件的models.Modelmodules={'models': ['__main__']})# Generate the schemaawait Tortoise.generate_schemas()if __name__ == '__main__':from tortoise import Tortoise, run_asyncrun_async(init())

如果需要自定义数据库字段的名称:使用source_field

username = fields.CharField(max_length=20, description="描述", unique=True, index=True, source_field="user_name")

2、单表常用操作

Create

# 单条新增 - 返回 <UserModel: 80f3e3d6-9b1b-4c58-9e77-f33f433184f8>
await UserModel.create(username="777", balance=22.135)# 批量新增 - 返回[<UserModel: 80f3e3d6-9b1b-4c58-9e77-f33f433684f8>, <UserModel: f47c9d3c-155e-4008-9a8e-a58e5a517537>]
await UserModel.bulk_create([UserModel(username=f'{i}', balance=i) for i in range(2)]
)

SQL 

INSERT INTO "tableName" 
("id","created","modified","username","nickname","gender","balance","is_admin","job_info")
VALUES 
('a6bf5564-b357-44f5-9132-a1be8f91f47b', '2022-11-13 02:19:35.754746+00:00', '2022-11-13 02:19:35.754759+00:00', '777', '777', 1, '22.14', 0, '{}')# 插入多条
INSERT INTO "tableName" ("id","created","modified","username","nickname","gender","balance","is_admin","job_info") 
VALUES 
('c8556714-5ad8-426b-9fc8-51b179500f81', '2022-11-13 02:19:35.756383+00:00', '2022-11-13 02:19:35.756390+00:00', '0', '777', 1, '0', 0, '{}'),
('0a94335d-3df6-4b4a-8982-408f9799a228', '2022-11-13 02:19:35.756407+00:00', '2022-11-13 02:19:35.756411+00:00', '1', '777', 1, '1', 0, '{}');

Delete

# 返回改动行数
await UserModel.filter(username="777").delete()

SQL

DELETE FROM "tableName" WHERE "username"='777'

Update


# 返回改动行数
await UserModel.filter(username="777").update(gender=0)# 批量更新
users = await UserModel.all()
for user in users:user.balance += 1.68await UserModel.bulk_update(users, fields=['balance'])

SQL

UPDATE "tableName" SET "gender"=0 WHERE "username"='777'# 批量更新
UPDATE "tableName" SET "gender"=0 WHERE "id" IN ('7aeb83f2-c0cb-4d21-a021-6cbe302a2b1e','3a18bbcd-163f-4574-afac-0b9f7ab89652')

Select

all

ps: 分组、排序、分页、聚合也适用 filter

# return [UserModel]
await UserModel.all()
"""
SELECT "gender","modified","nickname","created","balance","is_admin","job_info","username","id" FROM "tableName" ORDER BY "is_admin" ASC
"""# return [dict] - values 可过滤需要的字段
await UserModel.all().values('id', 'username')
"""
SELECT "id" "id","username" "username" FROM "tableName" ORDER BY "is_admin" ASC
"""# 排序
await UserModel.all().order_by('-created')
"""
SELECT "job_info","id","gender","username","modified","nickname","created","balance","is_admin" FROM "tableName" ORDER BY "created" DESC
"""# 分页
await UserModel.all().offset(3).limit(2)
"""
SELECT "nickname","username","created","job_info","is_admin","balance","gender","modified","id" FROM "tableName" ORDER BY "is_admin" ASC LIMIT 2, 3
"""# 分组 value_list 可过滤需要字段 return ((字段值, )) 使用聚合函数 + 分组
await UserModel.all().annotate(result=Sum('balance')).group_by('gender').value_list('gender', 'result')
"""
SELECT "gender" "gender",SUM(CAST("balance" AS NUMERIC)) "result" FROM "tableName" GROUP BY "gender"
"""# 统计 返回 数字
await UserModel.all().count()
"""
SELECT COUNT(*) FROM "tableName"
"""

get

# 根据条件查询符合的对象,条件需唯一 return UserModel
await UserModel.get(nickname='777')
"""
SELECT "id","job_info","created","nickname","is_admin","balance","modified","gender","username" FROM "tableName" WHERE "username"='0' ORDER BY "is_admin" ASC LIMIT 2
"""# 查询不到返回None,避免 出现对象不存在的异常
await UserModel.get_or_none(username=100)
"""
SELECT "id","nickname","balance","created","modified","is_admin","username","gender","job_info" FROM "tableName" WHERE "username"='100' ORDER BY "is_admin" ASC LIMIT 2
"""# 如果有就返回查询数据,没有就创建
await UserModel.get_or_create(username=19, balance=22.9)
"""
SELECT "id","nickname","balance","created","modified","is_admin","username","gender","job_info" FROM "tableName" WHERE "username"='19' AND "balance"='22.9' ORDER BY "is_admin" ASC LIMIT 2
"""

filter 条件过滤

# return [UserModel] 条件查询 gender=1
await UserModel.filter(gender=1).count()
# 性别为1 的平均余额
await UserModel.filter(gender=1).annotate(price=Avg('balance')).values('price')
"""
SELECT AVG(CAST("balance" AS NUMERIC)) "price" FROM "tableName" WHERE "gender"=1
"""# 各性别平均余额
await UserModel.annotate(price=Avg('balance')).group_by('gender').values('gender', 'price')
"""
SELECT "gender" "gender",AVG(CAST("balance" AS NUMERIC)) "price" FROM "tableName" GROUP BY "gender"
"""# 获取第一个符合条件的
await UserModel.filter(nickname=777).first()
"""
SELECT "nickname","gender","is_admin","created","balance","job_info","id","username","modified" FROM "tableName" WHERE "nickname"='777' ORDER BY "is_admin" ASC LIMIT 1
"""# get sql
UserModel.filter(nickname=777).sql()
"""
SELECT "nickname","gender","is_admin","created","balance","job_info","id","username","modified" FROM "tableName" WHERE "nickname"='777' ORDER BY "is_admin" ASC"""# 查询 gender 不为 1
await UserModel.exclude(gender=1)
"""
SELECT "balance","modified","nickname","is_admin","id","created","job_info","username","gender" FROM "tableName" WHERE NOT "gender"=1 ORDER BY "is_admin" ASC"""# 查询 gender 不为 1
await UserModel.filter(gender__not=1)
"""
SELECT "nickname","job_info","is_admin","created","gender","balance","modified","username","id" FROM "tableName" WHERE "gender"<>1 OR "gender" IS NULL ORDER BY "is_admin" ASC"""# https://tortoise.github.io/query.html?h=__conta#filtering
# 包含 7 忽略大小写 -》 like
await UserModel.filter(nickname__icontains='7')
"""
SELECT "nickname","created","id","balance","is_admin","job_info","modified","gender","username" FROM "tableName" WHERE UPPER(CAST("nickname" AS VARCHAR)) LIKE UPPER('%7%') ESCAPE '\' ORDER BY "is_admin" ASC
"""# between 0 and 10
await UserModel.filter(balance__range=[0, 10])
"""
SELECT "gender","balance","is_admin","modified","nickname","id","job_info","created","username" FROM "tableName" WHERE "balance" BETWEEN 0 AND 10 ORDER BY "is_admin" ASC
"""# 大于等于1
await UserModel.filter(gender__gte=1)
"""
SELECT "username","modified","gender","job_info","id","balance","is_admin","nickname","created" FROM "tableName" WHERE "gender">=1 ORDER BY "is_admin" ASC
"""# is null
await UserModel.filter(gender__isnull=True)
"""
SELECT "username","modified","gender","job_info","id","balance","is_admin","nickname","created" FROM "tableName" WHERE "gender" IS NULL ORDER BY "is_admin" ASC
"""await UserModel.get_or_create(username=7809, balance=99.22, job_info={"breed": "labrador","owner": {"name": "Boby","last": None,"other_pets": [{"name": "Fishy",}],},})
# json 字段 owner 下other pets第一个 name 不为Fishy
await UserModel.filter(job_info__filter={"owner__other_pets__0__name__not": "Fishy"})
"""
SELECT "username","nickname","created","gender","job_info","balance","is_admin","id","modified" FROM "tableName" WHERE "username"='7809' AND "balance"='99.22' AND "job_info"='{"breed":"labrador","owner":{"name":"Boby","last":null,"other_pets":[{"name":"Fishy"}]}}' ORDER BY "is_admin" ASC LIMIT 2
"""# 子查询
await UserModel.filter(pk=Subquery(UserModel.filter(username=777).values("id"))).first()
"""
SELECT "job_info","created","username","is_admin","gender","balance","modified","nickname","id" FROM "tableName" WHERE "id"=(SELECT "id" "id" FROM "tableName" WHERE "username"='777' ORDER BY "is_admin" ASC) ORDER BY "is_admin" ASC LIMIT 1
"""

filter Q&F&RawSQL

# or
# username 为 '777' 或者 gender 不为1
await UserModel.filter(Q(username=777) | Q(gender__not=1))
"""
SELECT "created","id","job_info","username","gender","modified","balance","is_admin","nickname" FROM "tableName" WHERE "username"='777' OR "gender"<>1 OR "gender" IS NULL ORDER BY "is_admin" ASC
"""
await UserModel.filter(Q(username=777), Q(gender__not=1), join_type='OR')
"""
SELECT "created","id","job_info","username","gender","modified","balance","is_admin","nickname" FROM "tableName" WHERE "username"='777' AND ("gender"<>1 OR "gender" IS NULL) ORDER BY "is_admin" ASC
"""
# ~Q 否定
await UserModel.filter(Q(username=777), ~Q(gender=1), join_type='OR')
"""
SELECT "created","id","job_info","username","gender","modified","balance","is_admin","nickname" FROM "tableName" WHERE "username"='777' AND NOT "gender"=1 ORDER BY "is_admin" ASC
"""
# Q and 查询username 为 777 并且gender不为1
await UserModel.filter(Q(username=777), Q(gender__not=1))
"""
SELECT "username","gender","is_admin","job_info","balance","id","created","nickname","modified" FROM "tableName" WHERE "username"='777' AND ("gender"<>1 OR "gender" IS NULL) ORDER BY "is_admin" ASC
"""await UserModel.filter(Q(username=777), Q(gender__not=1), join_type='AND')
"""
SELECT "username","gender","is_admin","job_info","balance","id","created","nickname","modified" FROM "tableName" WHERE "username"='777' AND ("gender"<>1 OR "gender" IS NULL) ORDER BY "is_admin" ASC
"""await UserModel.filter(username=777, gender__not=1)
"""
SELECT "username","gender","is_admin","job_info","balance","id","created","nickname","modified" FROM "tableName" WHERE "username"='777' AND ("gender"<>1 OR "gender" IS NULL) ORDER BY "is_admin" ASC
"""# 将结果的 余额 + 999
await UserModel.annotate(idp=F("balance")+999).values("balance", "idp")
"""
SELECT "balance" "balance","balance"+999 "idp" FROM "tableName"
"""# RawSQL 余额 + 999, 可在其中执行SQL语句
await UserModel.annotate(idp=RawSQL("balance + 999")).values("balance", "idp")
"""
SELECT "balance" "balance",balance + 999 "idp" FROM "tableName"
"""# RawSQL 统计
await UserModel.annotate(idp=RawSQL("count(id)")).values('idp')
"""
SELECT count(id) "idp" FROM "tableName"
"""

原生SQL


# 执行原生SQL,返回字典
conn = connections.get("default")
await conn.execute_query_dict("SELECT COUNT(*) FROM tableName WHERE username=(?)", ['777'])
"""
SELECT COUNT(*) FROM tableName WHERE username='777'
"""

3、一对一关系

PS:1个学生仅有一个详细信息

模型定义

class Student(models.Model):name = fields.CharField(max_length=20, description="name")# 与下面的related_name 字段名一致,仅得到友好提示info: fields.ReverseRelation["StudentDetail"]class StudentDetail(models.Model):age = fields.IntField(description='age')# Student Object 通过 info拿到 StudentDetail Object, 类型标注友好提示 code联想补充students: fields.OneToOneRelation[Student] = fields.OneToOneField('models.Student', related_name='info')

表信息 

CREATE TABLE "studentdetail" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"age" INT NOT NULL  /* age */,"student_id" INT NOT NULL UNIQUE REFERENCES "student" ("id") ON DELETE CASCADE
);
CREATE TABLE "student" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"name" VARCHAR(20) NOT NULL  /* name */
);

OneToOneField

  • model_name:相关模型的名称,格式为: samp: “{ app } . { model }”‘ format。
  • related_name:相关模型上的属性名,以反向解析外键
  • to_field: 对相关模型的属性名建立外键关系。如果未设置,则使用 pk, 关联模型上的某个建
  • on_delete:

    • field.CASCADE:指示如果相关模型被删除,则该模型应级联删除。
    • field.SET_DEFAULT:将字段重置为“ default”值,以防相关模型被删除。只能设置为字段具有“默认”设置。
    • field.SET_NULL:如果相关模型被删除,则将字段重置为 NULL。只能在字段设置为“ null = True”时设置。
    • field.RESTRICT:指示只要有外键指向相关模型删除,就会限制该删除。
  • db_constraint:默认值为 True,这几乎肯定是您想要的; 将其设置为 False 可能对数据完整性非常不利, 则为逻辑外建

CRUD

# create
student = await Student.create(name='7y')
await StudentDetail.create(age=18, students=student)
"""
INSERT INTO "student" ("name") VALUES ('7y')
# 15 为 student 的主键
INSERT INTO "studentdetail" ("age","students_id") VALUES (18,15)
"""# 改 只能改 某一张表的数据
await Student.filter(info__age=18).update(name='777')
"""
UPDATE "student" SET "name"=? FROM "student" "student_" LEFT OUTER JOIN "studentdetail" ON "student"."id"="studentdetail"."students_id" WHERE "studentdetail"."age"=18: ['777']
"""
await Student.filter(name='777').update(name='7y')
await StudentDetail.filter(students__name='777').update(age=18)# 查 学生名 7y 并且 学生 年龄 = 18 的数据 主表查从《关联表》表
res = await Student.filter(name='7y', info__age=18).first()
"""
SELECT "studentdetail"."age","studentdetail"."students_id","studentdetail"."id" FROM "studentdetail" LEFT OUTER JOIN "student" "studentdetail__students" ON "studentdetail__students"."id"="studentdetail"."students_id" WHERE "studentdetail__students"."name"='7y' LIMIT 1"""
# 通过res.related_name可获得被关联模型 StudentDetail
student_detail = await res.info.first()
print(student_detail.age) # 18res = (await StudentDetail.all().prefetch_related(Prefetch("students", queryset=Student.filter(name='7y'))).first())
print(await res.students.all().values())  # [{'id': 68, 'name': '7y'},]
"""
SELECT "students_id","age","id" FROM "studentdetail" LIMIT 1
SELECT "name","id" FROM "student" WHERE "name"='7y' AND "id" IN (68)
"""# 关联表查主表
res = await StudentDetail.filter(students__name='7y').first()
"""
SELECT "studentdetail"."age","studentdetail"."students_id","studentdetail"."id" FROM "studentdetail" LEFT OUTER JOIN "student" "studentdetail__students" ON "studentdetail__students"."id"="studentdetail"."students_id" WHERE "studentdetail__students"."name"='7y' LIMIT 1
"""
# 通过 res.students 获得 Student模型
student = await res.students.first()
print(student.name) # 7yres = await Student.filter(info__age=18).first().prefetch_related("info")
"""
SELECT "student"."name","student"."id" FROM "student" LEFT OUTER JOIN "studentdetail" ON "student"."id"="studentdetail"."students_id" WHERE "studentdetail"."age"=18 LIMIT 1
"""
print(res.info.age) # 18
"""
SELECT "students_id","age","id" FROM "studentdetail" WHERE "students_id" IN (68)
"""await StudentDetail.all().values('students__name', 'students__id', 'age')
"""
SELECT "studentdetail__students"."name" "students__name","studentdetail__students"."id" "students__id","studentdetail"."age" "age" FROM "studentdetail" LEFT OUTER JOIN "student" "studentdetail__students" ON "studentdetail__students"."id"="studentdetail"."students_id": None"""# 删 取决于 on_delete 策略
await Student.filter(name='7y').delete()

4、 一对多关系

PS:1个班有多名学生; 班级 (1) -》 学生(多),CRUD和 3. 一对一关系 类似

模型定义


class Class(models.Model):id = fields.IntField(pk=True, description="班级唯一标识")name = fields.CharField(max_length=10, description="班级名称")# 类型提示,仅用于Code 联想字段 匹配 下方关联的related_namestudents: fields.ReverseRelation["Student"]class Student(models.Model):"""学生"""id = fields.IntField(pk=True, description="学生唯一标识")name = fields.CharField(max_length=20, description="学生名称")# Class Object 通过 students 拿到 List[Student Object] , 类型标注友好提示 code联想补充# 生成外建; 字段名 + _to_field(默认主表的主键)my_class: fields.ForeignKeyRelation[Class] = fields.ForeignKeyField("models.Class", related_name='students',description="所属班级")

 表信息

CREATE TABLE "class" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL /* 班级唯一标识 */,"name" VARCHAR(10) NOT NULL  /* 班级名称 */
);CREATE TABLE "student" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL /* 学生唯一标识 */,"name" VARCHAR(20) NOT NULL  /* 学生名称 */,"my_class_id" INT NOT NULL REFERENCES "class" ("id") ON DELETE CASCADE /* 所属班级 */
);

ForeignKeyField

  • model_name:相关模型的名称,格式为: samp: “{ app } . { model }”‘ format。
  • related_name:相关模型上的属性名,以反向解析外键
  • to_field: 对相关模型的属性名建立外键关系。如果未设置,则使用 pk, 关联模型上的某个建
  • on_delete:

      • field.CASCADE:指示如果相关模型被删除,则该模型应级联删除。
      • field.RESTRICT:指示只要有外键指向相关模型删除,就会限制该删除。
      • field.SET_NULL:如果相关模型被删除,则将字段重置为 NULL。只能在字段设置为“ null = True”时设置。
      • field.SET_DEFAULT:将字段重置为“ default”值,以防相关模型被删除。只能设置为字段具有“默认”设置。
  • db_constraint:默认值为 True,这几乎肯定是您想要的; 将其设置为 False 可能对数据完整性非常不利, 则为逻辑外建

# create
class_obj = await Class.create(name='🚀班')
student_obj = await Student.create(name='7777777', my_class=class_obj)
# await Student.create(name='7777777', my_class=class_obj.id)
# await Student.create(name='7777777', my_class=class_obj.pk)
"""
INSERT INTO "class" ("name") VALUES (?): ['🚀班']
INSERT INTO "student" ("name","my_class_id") VALUES (?,?): ['7777777', 1]
"""# 通过表class(1) 获取 student(多)
for student in await class_obj.students.all():"""SELECT "id","name","my_class_id" FROM "student" WHERE "my_class_id"=4"""# pk 和 id 都是表示主键的意思print(student.name, student.id, student.pk)res = await Class.filter(id=3).first().prefetch_related("students")
print(await res.students.all().values())res = await Class.all().prefetch_related(Prefetch("students", queryset=Student.filter(my_class__name__not='7y').all())
)
print(await res[0].students.all().values())
"""
SELECT "student"."name","student"."id","student"."my_class_id" FROM "student" LEFT OUTER JOIN "class" "student__my_class" ON "student__my_class"."id"="student"."my_class_id" WHERE ("student__my_class"."name"<>'7y' OR "student__my_class"."name" IS NULL) AND "student"."my_class_id" IN (1,2,3,4,5,6)"""# 通过表 student(多) 获取 class(1)
print(await student_obj.my_class.all().values())
"""
SELECT "id" "id","name" "name" FROM "class"
"""res = await Student.filter(my_class__id__lt=2).all()
for cls in await res[0].my_class.all():print(cls)

5、多对多关系

模型定义


class Course(models.Model):"""课程表"""name = fields.CharField(max_length=20, description="课程名")students: fields.ManyToManyRelation["Student"]class Student(models.Model):name = fields.CharField(max_length=20)courses: fields.ManyToManyRelation[Course] = fields.ManyToManyField("models.Course",related_name="students")

表信息

CREATE TABLE "course" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"name" VARCHAR(20) NOT NULL  /* 课程名 */
);CREATE TABLE "student" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"name" VARCHAR(20) NOT NULL
);CREATE TABLE "student_course" ("student_id" INT NOT NULL REFERENCES "student" ("id") ON DELETE CASCADE,"course_id" INT NOT NULL REFERENCES "course" ("id") ON DELETE CASCADE
);

ManyToManyField

  • model_name:相关模型的名称,格式为: samp: “{ app } . { model }”‘ format。
  • related_name:相关模型上的属性名,以反向解析外键
  • to_field: 对相关模型的属性名建立外键关系。如果未设置,则使用 pk, 关联模型上的某个建
  • through:关联表的名称,默认当前表_关联表
  • forward_key:通过表的正向查找键。默认值通常是安全的。
  • backward_key:通过表的向后查找键。默认值通常是安全的。
  • on_delete:
    • field.CASCADE:指示如果相关模型被删除,则该模型应级联删除。
      • field.RESTRICT:指示只要有外键指向相关模型删除,就会限制该删除。
      • field.SET_NULL:如果相关模型被删除,则将字段重置为 NULL。只能在字段设置为“ null = True”时设置。
      • field.SET_DEFAULT:将字段重置为“ default”值,以防相关模型被删除。只能设置为字段具有“默认”设置。
  • db_constraint:默认值为 True,这几乎肯定是您想要的; 将其设置为 False 可能对数据完整性非常不利, 则为逻辑外建

CRUD

# Create student object
student = await Student.create(name='7y')
"""
INSERT INTO "student" ("name") VALUES (?): ['7y']
"""
# 2. course object
course = await Course.create(name='Python')
"""
INSERT INTO "course" ("name") VALUES (?): ['Python']
"""
# 3. student_courses object
await student.courses.add(course)
"""
INSERT INTO "student_course" ("course_id","student_id") VALUES (3,3)
"""
await student.courses
"""
SELECT "course"."id","course"."name" FROM "course" LEFT OUTER JOIN "student_course" ON "course"."id"="student_course"."course_id" WHERE "student_course"."student_id"=5
"""# student表 获取course
for course in await student.courses:print(course.id) # 5r = await Student.filter(courses=5).prefetch_related("courses")
"""
SELECT "sq0"."_backward_relation_key" "_backward_relation_key","course"."name" "name","course"."id" "id" FROM "course" JOIN (SELECT "student_id" "_backward_relation_key","course_id" "_forward_relation_key" FROM "student_course" WHERE "student_id" IN (5)) "sq0" ON "sq0"."_forward_relation_key"="course"."id""""
print(r)# course表获取 student
await course.students
"""
SELECT "student"."name","student"."id" FROM "student" LEFT OUTER JOIN "student_course" ON "student"."id"="student_course"."student_id" WHERE "student_course"."course_id"=7
"""await student.fetch_related("courses")
await course.fetch_related("students")# 去掉重复
await Student.filter(courses__name='Python').distinct()
"""
SELECT DISTINCT "student"."id","student"."name" FROM "student" LEFT OUTER JOIN "student_course" ON "student"."id"="student_course"."student_id" LEFT OUTER JOIN "course" ON "student_course"."course_id"="course"."id" WHERE "course"."name"='Python'
"""

6、事务 & 信号 & 迁移

信号

ps:在CRUD前可添加处理逻辑

Simple Examples - Tortoise ORM v0.1

模型定义&信号注册

class User(models.Model):name = fields.CharField(max_length=30)age = fields.IntField()@pre_save(User)
async def signal_pre_save(sender: "Type[User]", instance: User, using_db, update_fields
) -> None:"""save 前执行"""print("pre save...", sender, instance, using_db, update_fields)@post_save(User)
async def signal_post_save(sender: "Type[User]",instance: User,created: bool,using_db: "Optional[BaseDBAsyncClient]",update_fields: List[str],
) -> None:"""save 后执行"""print("post.save...", sender, instance, using_db, created, update_fields)@pre_delete(User)
async def signal_pre_delete(sender: "Type[User]", instance: User, using_db: "Optional[BaseDBAsyncClient]"
) -> None:print("pre delete ...", sender, instance, using_db)@post_delete(User)
async def signal_post_delete(sender: "Type[User]", instance: User, using_db: "Optional[BaseDBAsyncClient]"
) -> None:print("post delete.", sender, instance, using_db)

操作


user = await User.create(name="23", age=18)
print("1\n")
user.name = "7y"
print("2\n")
await user.save(update_fields=["name"])
print("3\n")
await user.delete()
print("4\n")await User.create(name="231", age=19)# 下面 不触发
await User.filter(age=19).update(name="78")
await User.filter(age=19).delete()

事务

ps:事务中的sql某一个出现异常及回滚

Simple Examples - Tortoise ORM v0.22.0 Documentation

# 前置条件表中不包含age 30 的数据
# 当我们执行下面语句, 第一行将创建好数据, 第二行因为数据不存在 而rasie一个异常
await User.create(name="Test", age=19)
await User.get(age=30)  # 数据不存在 rasie Object does not exist# 这时候我们通过,这行更加笃定
await User.filter(name="Test", age=19).first()# 如果把他们放到一个事务中 则创建成功后回回滚,最终查不出数据 / 最终没写入到数据库

in_transaction 上下文管理器

# 1.事务方式一 in_transaction 上下文管理器, 可以debug查看更直观
try:async with in_transaction() as connection:# 1. 创建await User.create(name="Test", age=19)# 2. 创建是否成功print(await User.filter(name="Test", age=19).first())# 3. 报个错await User.get(age=30)  # 数据不存在 rasie Object does not exist
except OperationalError as e:print(e)
# 4. 确认是否回滚
print(await User.all())

atomic 装饰器

@atomic()
async def bound_to_fall():# 1. 创建await User.create(name="Test", age=19)# 2. 创建是否成功print(await User.filter(name="Test", age=19).first())# 3. 报个错
try:await bound_to_fall()
except OperationalError as e:print(e)
# 4. 确认是否回滚, 如果查到了 说明回滚失败 还是新增了数据
print(await User.filter(name="Test", age=19).first())

迁移

ps: 通过orm 生成 sql 再到表《按版本管理》

Migration - Tortoise ORM v0.22.0 Documentation

pip install aerich aiomysql# aerich -h 查看帮助文档downgrade  降级至指定版本heads      Show current available heads in migrate location.history    List all migrate items.init       Init config file and generate root migrate location.init-db    Generate schema and generate app migrate location.生成模式并生成应用程序迁移位置。migrate    Generate migrate changes file.生成迁移更改文件。upgrade    Upgrade to latest version.升级到最新版本。
TORTOISE_ORM = {# 连接信息"connections": {"default": "mysql://root:123456@127.0.0.1:3306/test"},"apps": {"models": {# model 信息# "models": ["more_more", "aerich.models", "table", "one_more"],"models": ["models", "aerich.models"], # 把需要的模型导进一个module 直接使用module"default_connection": "default",},},
}
# 1. 先初始化
aerich init -t conf.TORTOISE_ORM
# Success create migrate location ./migrations
# Success write config to pyproject.toml# 2. 初次使用生成表 和 迁移文件
aerich init-db
# Success create app migrate location migrations/models
# Success generate schema for app "models"# 3. 模型字段有变更时, 生成迁移文件
aerich migrate --name add_name_desc
# Success migrate 1_20221114234032_add_name_desc.py# 4. 迁移文件生成表
aerich upgrade
# Success upgrade 1_20221114234032_add_name_desc.py# 5. 迁移历史
aerich history
# 0_20221114233906_init.py
# 1_20221114234032_add_name_desc.py# 6. 回到上一次迁移
aerich downgrade
# Downgrade is dangerous, which maybe lose your data, are you sure? [y/N]: 

7、主从数据库、读写分离

Router - Tortoise ORM v0.22.0 Documentation

1. 搭建MySQL主从
Docker部署Mysql8.0.20并配置主从复制 - C3Stones - 博客园
ps: m1芯片可以参考下面拉取镜像

m1 master

docker run --name mastermysql -d -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /Users/qy_air/mysql/master/data:/var/lib/mysql -v /Users/qy_air/mysql/master/conf/my.cnf:/etc/mysql/my.cnf mysql/mysql-server

m1 salve

docker run --name slavemysql -d -p 3308:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /Users/qy_air/mysql/slave/data:/var/lib/mysql -v /Users/qy_air/mysql/slave/conf/my.cnf:/etc/mysql/my.cnf mysql/mysql-server

Tortoise 读写分离

"""
This example to use router to implement read/write separation
"""
from typing import Typefrom tortoise import Tortoise, fields, run_async
from tortoise.models import Modelclass Event(Model):id = fields.IntField(pk=True)name = fields.TextField()datetime = fields.DatetimeField(null=True)class Meta:table = "event"def __str__(self):return self.nameclass Router:def db_for_read(self, model: Type[Model]):return "slave"def db_for_write(self, model: Type[Model]):return "master"async def run():config = {"connections": {"master": "mysql://root:123456@127.0.0.1:3306/test","slave": "mysql://root:123456@127.0.0.1:3307/test"},"apps": {"models": {"models": ["__main__"],"default_connection": "master",}},"routers": ["__main__.Router"],"use_tz": False,"timezone": "UTC",}await Tortoise.init(config=config)await Tortoise.generate_schemas()# this will use connection masterevent = await Event.create(name="Test")# this will use connection slaveawait Event.get(pk=event.pk)if __name__ == "__main__":run_async(run())

8、序列化

因为这里的Pydantic我通常在FastAPI中有使用场景所以这里结合了pydantic 方便看序列化出来的模型效果

code

"""
This example demonstrates pydantic serialisation
已知问题:表中的关联字段 序列化 pydantic模型会被忽略,出现这种问题,可继承生成出来的schema 再把关系字段 写进去
"""
from typing import Optional, Listfrom tortoise import Tortoise, fields
from tortoise.contrib.pydantic import pydantic_model_creator, pydantic_queryset_creator
from tortoise.models import Modelasync def connect():await Tortoise.init(db_url="sqlite://:memory:", modules={"models": ["__main__"]})await Tortoise.generate_schemas()class User(Model):name = fields.CharField(max_length=20)loves = fields.JSONField(default=list)age = fields.IntField()password = fields.CharField(max_length=120)parent = fields.ForeignKeyField("models.User", related_name="pid", null=True, default=True)# 关系表序列化def length(self) -> int:"""计算属性 pydantic"""return len(self.name)# https://tortoise.github.io/contrib/pydantic.html?h=pydanticmeta#inheritanceclass PydanticMeta:allow_cycles: bool = False # 关系递归引用backward_relations: bool = True # 递归关系config_class = None # 自定义配置类exclude_raw_fields: bool = True # 排除原始的关系字段 字段包含_idmax_recursion: int = 3 # 最大递归级别sort_alphabetically: bool = False # 按字母排序# 生成模型排除字段exclude = ("created_at",)# Let's include two callables as computed columns 计算属性列computed = () # 计算属性,计算属性 必须带返回值类型Tortoise.init_models(["__main__"], "models")# model(ORM) to  schema(Pydantic) 序列化   ||| schema(Pydantic) to  model(ORM) 反序列化# exclude 排除 include 包含Default = pydantic_model_creator(User, name="default")  # 所有字段
UserSchema = pydantic_model_creator(User, name="UserInput", exclude_readonly=True) # 只读 主键、
IncludeName = pydantic_model_creator(User, name="UserName", include=("name", ))
Computed = pydantic_model_creator(User, name="computed", computed=("length",))
UserSchemaOut = pydantic_model_creator(User, exclude=("password",))
UserSchemaList = pydantic_queryset_creator(User)from fastapi import FastAPI, APIRouterapp = FastAPI(title="Tortoise ORM Pydantic 序列化", on_startup=[connect], on_shutdown=[Tortoise.close_connections])serialization = APIRouter(tags=['model 序列化 pydantic - 需要model作为参数'])@serialization.post("/Default", summary="Default - 根据model全量")
def defa(data: Default):pass@serialization.post("/int", summary="UserSchema - 排除只读")
def inp(data: UserSchema):pass@serialization.post("/demo", summary="IncludeName - 仅包含name")
def ipn(data: IncludeName):pass@serialization.post("/Computed", summary="Computed - 添加计算属性")
def Comp(data: Computed):pass@serialization.post("/out", summary="UserSchemaOut - 排除password")
def out(data: UserSchemaOut):pass@serialization.post("/list", summary="UserSchemaList - 列表")
def li(data: UserSchemaList):passdeserialization = APIRouter(tags=["pydantic 反序列化 model - 需要model作为参数"])class Input(UserSchema):parent: Optional[int]@deserialization.post("/user", summary="from_tortoise_orm - 单个model")
async def add(data: Input):print(data)obj = await User.create(**data.dict())# 反序列化 需要一个Model 对象return await UserSchemaOut.from_tortoise_orm(obj)@deserialization.get("/user", summary="用户列表", response_model=UserSchemaList)
async def arr():# 反序列化 需要一个QuerySet 对象return await UserSchemaList.from_queryset(User.all())@deserialization.get("/user/{id}", summary="用户详细")
async def info(id: int):return await UserSchemaOut.from_queryset_single(User.filter(id=id).first())@deserialization.get("/user/q/{id}", summary="用户查询", response_model=List[UserSchemaOut])
async def query():return await UserSchemaOut.from_queryset(User.all())# return await UserSchemaList.from_queryset(User.all())# return await UserSchemaOut.from_queryset_single(User.all())app.include_router(serialization)
app.include_router(deserialization)if __name__ == '__main__':import uvicornuvicorn.run("__main__:app", reload=True)

序列化

@serialization.post("/Default", summary="Default - 根据model全量")
def defa(data: Default):pass"""
Default = pydantic_model_creator(User, name="default")  # 所有字段序列化的model
{"id": 2147483647,"name": "string","loves": "string","age": 2147483647,"password": "string"
}"""@serialization.post("/int", summary="UserSchema - 排除只读")
def inp(data: UserSchema):pass"""
UserSchema = pydantic_model_creator(User, name="UserInput", exclude_readonly=True)序列化的model{"name": "string","loves": "string","age": 2147483647,"password": "string"
}"""@serialization.post("/demo", summary="IncludeName - 仅包含name")
def ipn(data: IncludeName):pass"""
IncludeName = pydantic_model_creator(User, name="UserName", include=("name", )){"name": "string"
}"""@serialization.post("/Computed", summary="Computed - 添加计算属性")
def Comp(data: Computed):pass"""
Computed = pydantic_model_creator(User, name="computed", computed=("length",)){"id": 2147483647,"name": "string","loves": "string","age": 2147483647,"password": "string","length": 0
}
"""@serialization.post("/out", summary="UserSchemaOut - 排除password")
def out(data: UserSchemaOut):pass
"""
UserSchemaOut = pydantic_model_creator(User, exclude=("password",))
{"id": 2147483647,"name": "string","loves": "string","age": 2147483647
}"""@serialization.post("/list", summary="UserSchemaList - 列表")
def li(data: UserSchemaList):pass
"""
UserSchemaList = pydantic_queryset_creator(User)[{"id": 2147483647,"name": "string","loves": "string","age": 2147483647}
]
"""

models.Model 转 Pydantic Model

"""
参数
:param cls: The Tortoise Model
:param name: 显式指定自定义名称,而不是生成的名称<schmea 中展现>
:param exclude: 要从提供的模型中排除的额外字段。
:param include: 要从提供的模型中包括的额外字段。
:param computed: 从提供的模型中包含额外的计算字段(orm中不存在的)。
:param optional: 提供的模型的额外可选字段.
:param allow_cycles: Do we allow any cycles in the generated model?
我们在生成的模型中允许任何循环吗
这只对递归/自引用模型有用。值“ False”(默认值)将防止任何和所有的回溯。
This is only useful for recursive/self-referential models.A value of ``False`` (the default) will prevent any and all backtracking.
:param sort_alphabetically: Sort the parameters alphabetically instead of Field-definition order.
按字母顺序排序参数,而不是按字段定义顺序。
The default order would be:* Field definition order +
* order of reverse relations (as discovered) +
* order of computed functions (as provided).
:param exclude_readonly: Build a subset model that excludes any readonly fields
构建一个排除任何只读字段的子集模型
:param meta_override: A PydanticMeta class to override model's values.
用于覆盖模型值的 PydanticMeta 类。
"""UserSchema = pydantic_model_creator(User, exclude_readonly=True, exclude=("password",))print(UserSchema.schema())# 反序列化Modelobj = await User.create(name=123, age=18, passowrd=123)# 自动预取所有关系 如果不需要/或者想同步 则使用from_ormawait UserSchema.from_tortoise_orm(obj)UserSchema.from_orm(obj)

models.Model 转 List Pydantci Model

"""
参数
:param cls: The Tortoise Model
:param name: 显式指定自定义名称,而不是生成的名称<schmea 中展现>
:param exclude: 要从提供的模型中排除的额外字段。
:param include: 要从提供的模型中包括的额外字段。
:param computed: 从提供的模型中包含额外的计算字段(orm中不存在的)。
:param allow_cycles: Do we allow any cycles in the generated model?
我们在生成的模型中允许任何循环吗
这只对递归/自引用模型有用。值“ False”(默认值)将防止任何和所有的回溯。
This is only useful for recursive/self-referential models.A value of ``False`` (the default) will prevent any and all backtracking.
:param sort_alphabetically: Sort the parameters alphabetically instead of Field-definition order.
按字母顺序排序参数,而不是按字段定义顺序。
The default order would be:* Field definition order +
* order of reverse relations (as discovered) +
* order of computed functions (as provided).
"""UserSchemaList = pydantic_queryset_creator(User)print(UserSchemaList.schema())

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/61780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【大数据学习 | Spark-Core】关于distinct算子

只有shuffle类的算子能够修改分区数量&#xff0c;这些算子不仅仅存在自己的功能&#xff0c;比如分组算子groupBy&#xff0c;它的功能是分组但是却可以修改分区。 而这里我们要讲的distinct算子也是一个shuffle类的算子。即可以修改分区。 scala> val arr Array(1,1,2,…

java基础概念36:正则表达式1

一、正则表达式的作用 作用一&#xff1a;校验字符串是否满足规则&#xff1b;作用二&#xff1a;在一段文本中查找满足要求的内容。——爬虫 二、正则表达式 2-1、字符类 示例&#xff1a; public static void main(String[] args) {System.out.println("a".matc…

oracle的静态注册和动态注册

oracle的静态注册和动态注册 静态注册&#xff1a; 静态注册 : 指将实例的相关信息手动告知 listener 侦 听 器 &#xff0c; 可以使用netmgr,netca,oem 以及直接 vi listener.ora 文件来实现静态注册&#xff0c;在动态注册不稳定时使用&#xff0c;特点是&#xff1a;稳定&…

html+js实现图片的放大缩小等比缩放翻转,自动播放切换,顺逆时针旋转

效果图&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>图片预览</title><sty…

Selenium+Java(19):使用IDEA的Selenium插件辅助超快速编写Pages

前言 或是惊叹于Selenium对于IDEA的支持已经达到了这样的地步,又或是由于这个好用的小工具的入口就在那里,它已经陪伴了我这么久,而我这么久的时间却都没有发现它。在突然发现这个功能的一瞬间,真的是喜悦感爆棚,于是赶快写下了这篇文章。希望可以帮助到其他同样在做UI自动…

知识付费系统-直播+讲师入驻+课程售卖+商城系统-v2.1.9版本搭建以及资源分享下载+附带完整安装步骤

知识付费系统-直播讲师入驻课程售卖商城系统-v2.1.9版本搭建以及资源分享下载 这是一款很棒&#xff0c;功能很强大的知识付费系统。 源码下载本帖已经绑定&#xff0c;可直接去下载。 1&#xff0c;源码上传 宝塔一键安装后&#xff0c;添加网站上传源码&#xff0c; 2&…

栈的应用,力扣394.字符串解码力扣946.验证栈序列力扣429.N叉树的层序遍历力扣103.二叉树的锯齿形层序遍历

目录 力扣394.字符串解码 力扣946.验证栈序列 力扣429.N叉树的层序遍历 力扣103.二叉树的锯齿形层序遍历 力扣394.字符串解码 看见括号&#xff0c;由内而外&#xff0c;转向用栈解决。使用两个栈处理&#xff0c;一个用String,一个用Integer 遇到数字:提取数字放入到数字栈…

408代码类复习--图类

图类 Author&#xff1a;Joanh_Lan Personal Blog Links&#xff1a;Joanh_LanのCSDN博客 备注&#xff1a; 个人复习版本 不保证完全正确&#xff0c;理性参考&#xff08;不背锅i哦&#xff09; &#xff08;&#xff1a;&#xff08;&#xff1a;&#xff08;&#xff…

Maven的安装——给Idea配置Maven

一、什么是Maven? Maven是一个开源的项目管理工具&#xff0c;它主要用于Java项目的构建、依赖管理和项目生命周期管理。 二、准备环境 maven安装之前&#xff0c;我们要先安装jdk&#xff0c;确保你已经安装了jdk环境。可以通过【win】【r】打开任务管理器&#xff0c;输入…

linux 常用命令指南(存储分区、存储挂载、docker迁移)

前言&#xff1a;由于目前机器存储空间不够&#xff0c;所以‘斥巨资’加了一块2T的机械硬盘&#xff0c;下面是对linux扩容的一系列操作&#xff0c;包含了磁盘空间的创建、删除&#xff1b;存储挂载&#xff1b;docker迁移&#xff1b;anaconda3迁移等。 一、存储分区 1.1 …

OpenCvSharp Demo 饱和度、明度、对比度、锐化、阴影、高光、色温实现滤镜效果

目录 效果 风景-天空滤镜 人像—酷感冷艳滤镜 美食—鲜美滤镜 美食—巧克力滤镜 项目 代码 参考 下载 效果 风景-天空滤镜 人像—酷感冷艳滤镜 美食—鲜美滤镜 美食—巧克力滤镜 项目 代码 using OpenCvSharp; using System; using System.Diagnostics; using Syst…

Easyexcel(4-模板文件)

相关文章链接 Easyexcel&#xff08;1-注解使用&#xff09;Easyexcel&#xff08;2-文件读取&#xff09;Easyexcel&#xff08;3-文件导出&#xff09;Easyexcel&#xff08;4-模板文件&#xff09; 文件导出 获取 resources 目录下的文件&#xff0c;使用 withTemplate 获…

迁移学习理论与应用

迁移学习&#xff08;Transfer Learning&#xff09;是一种机器学习技术&#xff0c;旨在将一个任务&#xff08;源任务&#xff09;上学到的知识迁移到另一个相关但不完全相同的任务&#xff08;目标任务&#xff09;上&#xff0c;从而提高目标任务的学习效果。这种方法的核心…

近期两篇NeRF/3DGS-based SLAM方案赏析:TS-SLAM and MBA-SLAM

原文链接&#xff1a;近期两篇NeRF/3DGS-based SLAM方案赏析&#xff1a;TS-SLAM and MBA-SLAM paper1&#xff1a;TS-SLAM: 基于轨迹平滑约束优化的神经辐射场SLAM方法 导读 本文提出了TS-SLAM&#xff0c;一种改进的基于神经辐射场&#xff08;NeRF&#xff09;的SLAM方法…

游戏引擎学习第20天

视频参考:https://www.bilibili.com/video/BV1VkBCYmExt 解释 off-by-one 错误 从演讲者的视角&#xff1a;对代码问题的剖析与修复过程 问题的起因 演讲者提到&#xff0c;他可能无意中在代码中造成了一个错误&#xff0c;这与“调试时间标记索引”有关。他发现了一个逻辑问题…

《鸿蒙系统:开启智能新时代的璀璨之星》

一、鸿蒙系统&#xff1a;崛起之路 鸿蒙系统的发展历程堪称一部科技创新的传奇。2012 年&#xff0c;华为前瞻性地启动鸿蒙系统研发项目&#xff0c;彼时或许很少有人能预见到它未来的辉煌。2019 年&#xff0c;鸿蒙系统首个开发者预览版的发布&#xff0c;如同夜空中的一颗璀…

SQL注入--DNSlog外带注入--理论

什么是DNSlog? DNS的作用是将域名解析为IP 而DNSlog就是存储在DNS服务器上的域名信息&#xff0c;它记录着用户对域名访问信息。可以理解为DNS服务器上的日志文件。 多级域名 比如blog.csdn.net&#xff0c;以点为分隔&#xff0c;从右向左依次是顶级域名、二级域名、三级域…

python: Serialize and Deserialize complex JSON using jsonpickle

# encoding: utf-8 # 版权所有 2024 ©涂聚文有限公司 # 许可信息查看&#xff1a;言語成了邀功盡責的功臣&#xff0c;還需要行爲每日來值班嗎 # Serialize and Deserialize complex JSON in Python # 描述&#xff1a;pip install jsonpickle https://github.com/jsonpi…

基于图的去中心化社会推荐过滤器

目录 原论文研究背景与研究意义概述论文所提出算法的主要贡献GDSRec算法原理与流程问题定义去中心化图&#xff08;decentralized graph&#xff09;所提出方法(三种并行建模)用户建模&#xff08;user modelling&#xff09; 模版代码讲解main.py顶层文件&#xff1a;用于集成…

计算机的错误计算(一百六十三)

摘要 四个算式“sin(0.00024/2)^2”、“(1-cos(0.00024))/2”、“(1-sqrt(1-sin(0.00024)^2))/2”以及“sin(0.00024)^2/(22*sqrt(1-sin(0.00024)^2))”是等价的。但是&#xff0c;在 MATLAB 中计算它们&#xff0c;输出不完全一致&#xff1a;中间两个算式的输出中含有错误数…