FastApi教程
FastAPI框架
fastapi
,一个用于构建 API 的现代、快速(高性能)的web框架。
fastapi
是建立在Starlette和Pydantic基础上的,Pydantic是一个基于Python类型提示来定义数据验证、序列化和文档的库。Starlette是一种轻量级的ASGI框架/工具包,是构建高性能Asyncio服务的理性选择。
- 快速:可与 NodeJS 和 Go 比肩的
极高性能
(归功于Starlette
和Pydantic
),是最快的 Python web 框架之一。- 高效编码:提高功能开发速度约 200% 至 300%。
- 更少bug:减少约 40% 的人为(开发者)导致错误。
- 智能:极佳的编辑器支持。处处皆可自动补全,减少调试时间。
- 简单:设计的
易于使用和学习
,阅读文档的时间更短。- 简短:使代码重复最小化。通过不同的参数声明实现丰富功能。
- 健壮:生产可用级别的代码。还有
自动生成的交互式文档
。
依赖:Python 3.6 及更高版本,FastAPI 站在以下巨人的肩膀之上
Starlette 负责 web 部分(Asyncio)
Pydantic 负责数据部分(类型提示)
FastApi是站在前人肩膀上,集成了多种框架的优点的新秀框架。它出现的比较晚,2018年底才发布在github上。广泛应用于当前各种前后端分离的项目开发,测试运维自动化以及微服务的场景中。
一、预备知识点
1.1、http协议
1. 什么是请求头请求体,响应头响应体
2. URL地址包括什么
3. get请求和post请求到底是什么
4. Content-Type是什么
1.2、简介
HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于万维网(WWW:World Wide Web )服务器与本地浏览器之间传输超文本的传送协议。HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。
1.3、http协议特性
(1) 基于TCP/IP协议 http协议是基于TCP/IP协议之上的应用层协议。
(2) 基于请求-响应模式 HTTP协议规定,请求从客户端发出,最后服务器端响应该请求并 返回。换句话说,肯定是先从客户端开始建立通信的,服务器端在没有 接收到请求之前不会发送响应
(3) 无状态保存 HTTP是一种不保存状态,即无状态(stateless)协议。HTTP协议 自身不对请求和响应之间的通信状态进行保存。也就是说在HTTP这个 级别,协议对于发送过的请求或响应都不做持久化处理。 使用HTTP协议,每当有新的请求发送时,就会有对应的新响应产 生。协议本身并不保留之前一切的请求或响应报文的信息。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计成 如此简单的。
(4) 短连接 HTTP1.0默认使用的是短连接。浏览器和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。 HTTP/1.1起,默认使用长连接。要使用长连接,客户端和服务器的HTTP首部的Connection都要设置为keep-alive,才能支持长连接。 HTTP长连接,指的是复用TCP连接。多个HTTP请求可以复用同一个TCP连接,这就节省了TCP连接建立和断开的消耗。
http协议包含由浏览器发送数据到服务器需要遵循的请求协议与服务器发送数据到浏览器需要遵循的请求协议。用于HTTP协议交互的信被为HTTP报文。请求端(客户端)的HTTP报文 做请求报文,响应端(服务器端)的 做响应报文。HTTP报文本身是由多行数据构成的字文本。
一个完整的URL包括:协议、ip、端口、路径、参数
例如: 百度安全验证 其中https是协议,www.baidu.com 是IP,端口默认80,/s是路径,参数是wd=yuan
请求方式: get与post请求
- GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditBook?name=test1&id=123456. POST方法是把提交的数据放在HTTP包的请求体中.
- GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制
响应状态码:状态码的职 是当客户端向服务器端发送请求时, 返回的请求 结果。借助状态码,用户可以知道服务器端是正常 理了请求,还是出 现了 。状态码如200 OK,以3位数字和原因 组成。
1.4、api接口
在开发Web应用中,有两种应用模式:
- 前后端不分离[客户端看到的内容和所有界面效果都是由服务端提供出来的。]
2.前后端分离【把前端的界面效果(html,css,js分离到另一个服务端,python服务端只需要返回数据即可)】前端形成一个独立的网站,服务端构成一个独立的网站
应用程序编程接口(Application Programming Interface,API接口),就是应用程序对外提供了一个操作数据的入口,这个入口可以是一个函数或类方法,也可以是一个url地址或者一个网络地址。当客户端调用这个入口,应用程序则会执行对应代码操作,给客户端完成相对应的功能。
当然,api接口在工作中是比较常见的开发内容,有时候,我们会调用其他人编写的api接口,有时候,我们也需要提供api接口给其他人操作。由此就会带来一个问题,api接口往往都是一个函数、类方法、或者url或其他网络地址,不断是哪一种,当api接口编写过程中,我们都要考虑一个问题就是这个接口应该怎么编写?接口怎么写的更加容易维护和清晰,这就需要大家在调用或者编写api接口的时候要有一个明确的编写规范!!!
为了在团队内部形成共识、防止个人习惯差异引起的混乱,我们都需要找到一种大家都觉得很好的接口实现规范,而且这种规范能够让后端写的接口,用途一目了然,减少客户端和服务端双方之间的合作成本。
目前市面上大部分公司开发人员使用的接口实现规范主要有:restful、RPC。
REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。 它首次出现在2000年Roy Fielding的博士论文中。
RESTful是一种专门为Web 开发而定义API接口的设计风格,尤其适用于前后端分离的应用模式中。
关键:面向资源开发
这种风格的理念认为后端开发任务就是提供数据的,对外提供的是数据资源的访问接口,所以在定义接口时,客户端访问的URL路径就表示这种要操作的数据资源。
而对于数据资源分别使用POST、DELETE、GET、UPDATE等请求动作来表达对数据的增删查改。
请求方法 | 请求地址 | 后端操作 |
---|---|---|
POST | /student/ | 增加学生 |
GET | /student/ | 获取所有学生 |
GET | /student/1 | 获取id为1的学生 |
PUT | /student/1 | 修改id为1的学生 |
DELETE | /student/1 | 删除id为1的学生 |
restful规范是一种通用的规范,不限制语言和开发框架的使用。事实上,我们可以使用任何一门语言,任何一个框架都可以实现符合restful规范的API接口。
二、quick start
安装:pip install fastapi
你还会需要一个 ASGI 服务器,生产环境可以使用 Uvicorn
pip install uvicorn
代码:
from fastapi import FastAPI # FastAPI 是一个为你的 API 提供了所有功能的 Python 类。app = FastAPI() # 这个实例将是创建你所有 API 的主要交互对象。这个 app 同样在如下命令中被 uvicorn 所引用@app.get("/")
async def root():return {"message": "Hello frank"}
通过以下命令运行服务器:
uvicorn main:app --reload
也可以直接运行:
if __name__ == '__main__':import uvicornuvicorn.run("main:app", host="127.0.0.1", port=8080, debug=True, reload=True)
(1)导入 FastAPI。
(2)创建一个 app 实例。
(3)编写一个路径操作装饰器(如 @app.get("/"))。
(4)编写一个路径操作函数(如上面的 def root(): …)
(5)定义返回值
(6)运行开发服务器(如 uvicorn main:app –reload)
此外,fastapi有着非常棒的交互式 API 文档,这一点很吸引人。
跳转到 http://127.0.0.1:8000/docs。你将会看到自动生成的交互式 API 文档。
三、路径操作
fastapi支持各种请求方式:
@app.get()
@app.post()
@app.put()
@app.patch()
@app.delete()
@app.options()
@app.head()
@app.trace()
from typing import Unionfrom fastapi import FastAPIapp = FastAPI()@app.get("/get")
def get_test():return {"method": "get方法"}@app.post("/post")
def post_test():return {"method": "post方法"}@app.put("/put")
def put_test():return {"method": "put方法"}@app.delete("/delete")
def delete_test():return {"method": "delete方法"}
路径操作装饰器参数:
@app.post("/items/{item_id}",response_model=Item,status_code=status.HTTP_200_OK,tags=["AAA"],summary="this is summary",description="this is description",response_description= "this is response_description",deprecated=False,
)
include_router
main.py
from typing import Unionfrom fastapi import FastAPI
import uvicornfrom apps import app01, app02app = FastAPI()app.include_router(app01, prefix="/app01", tags=["第一章节:商城接口", ])
app.include_router(app02, prefix="/app02", tags=["第二章节:用户中心接口", ])if __name__ == '__main__':uvicorn.run("main:app", host="127.0.0.1", port=8080, debug=True, reload=True)
与main.py同级目录apps:
# __init__.py
from .app01 import app01
from .app02 import app02
from fastapi import APIRouterapp01 = APIRouter()@app01.get("/shop/food")
def shop_food():return {"shop": "food"}@app01.get("/shop/bed")
def shop_food():return {"shop": "bed"}
from fastapi import APIRouterapp02 = APIRouter()@app02.post("/user/login")
def user_login():return {"user": "login"}@app02.post("/user/reg")
def user_reg():return {"user": "reg"}
四、请求与响应
1、路径参数
(1)基本用法
以使用与 Python 格式化字符串相同的语法来声明路径"参数"或"变量":
@app.get("/user/{user_id}")
def get_user(user_id):print(user_id, type(user_id))return {"user_id": user_id}
路径参数 user_id
的值将作为参数 user_id
传递给你的函数。
(2)有类型的路径参数
你可以使用标准的 Python 类型标注为函数中的路径参数声明类型。
@app.get("/user/{user_id}")
def get_user(user_id: int):print(user_id, type(user_id))return {"user_id": user_id}
在这个例子中,user_id
被声明为 int
类型。
这将为你的函数提供编辑器支持,包括错误检查、代码补全等等。
(3)注意顺序
在创建路径操作时,你会发现有些情况下路径是固定的。
比如 /users/me
,我们假设它用来获取关于当前用户的数据.
然后,你还可以使用路径 /user/{username}
来通过用户名 获取关于特定用户的数据。
由于路径操作是按顺序依次运行的,你需要确保路径 /user/me
声明在路径 /user/{username}
之前:
@app.get("/user/me")
async def read_user_me():return {"username": "the current user"}@app.get("/user/{username}")
async def read_user(username: str):return {"username": username}
否则,/user/{username}
的路径还将与 /user/me
相匹配,“认为"自己正在接收一个值为 "me"
的 username
参数。
2、查询参数(请求参数)
路径函数中声明不属于路径参数的其他函数参数时,它们将被自动解释为"查询字符串"参数,就是 url? 之后用&
分割的 key-value 键值对。
@app.get("/jobs/{kd}")
async def search_jobs(kd: str, city: Union[str, None] = None, xl: Union[str, None] = None): # 有默认值即可选,否则必选if city or xl:return {"kd": kd, "city": city, "xl": xl}return {"kd": kd}
在这个例子中,函数参数 city
和xl
是可选的,并且默认值为 None
。
自python3.5开始,PEP484为python引入了类型注解(type hints),typing的主要作用有:
- 类型检查,防止运行时出现参数、返回值类型不符。
- 作为开发文档附加说明,方便使用者调用时传入和返回参数类型。
- 模块加入不会影响程序的运行不会报正式的错误,pycharm支持typing检查错误时会出现黄色警告。
type hints
主要是要指示函数的输入和输出的数据类型,数据类型在typing 包中,基本类型有str list dict等等,
Union 是当有多种可能的数据类型时使用,比如函数有可能根据不同情况有时返回str或返回list,那么就可以写成Union[list, str] Optional 是Union的一个简化, 当 数据类型中有可能是None时,比如有可能是str也有可能是None,则Optional[str], 相当于Union[str, None]
3、请求体数据
当你需要将数据从客户端(例如浏览器)发送给 API 时,你将其作为「请求体」发送。请求体是客户端发送给 API 的数据。响应体是 API 发送给客户端的数据。
FastAPI 基于 Pydantic
,Pydantic
主要用来做类型强制检查(校验数据)。不符合类型要求就会抛出异常。
对于 API 服务,支持类型检查非常有用,会让服务更加健壮,也会加快开发速度,因为开发者再也不用自己写一行一行的做类型检查。
安装上手pip install pydantic
from typing import Union, List, Optionalfrom fastapi import FastAPI
from pydantic import BaseModel, Field, ValidationError, validator
import uvicorn
from datetime import dateclass Addr(BaseModel):province: strcity: strclass User(BaseModel):name = 'root'age: int = Field(default=0, lt=100, gt=0)birth: Optional[date] = Nonefriends: List[int] = []description: Union[str, None] = None# addr: Union[Addr, None] = None # 类型嵌套@validator('name')def name_must_alpha(cls, v):assert v.isalpha(), 'name must be alpha'return vclass Data(BaseModel): # 类型嵌套users: List[User]app = FastAPI()@app.post("/data/")
async def create_data(data: Data):# 添加数据库return dataif __name__ == '__main__':try:User(name="",...)except ValidationError as e:print(e.json())
和声明查询参数时一样,当一个模型属性具有默认值时,它不是必需的。否则它是一个必需属性。将默认值设为 None
可使其成为可选属性。
FastAPI 会自动将定义的模型类转化为JSON Schema
,Schema 成为 OpenAPI 生成模式的一部分,并显示在 API 交互文档中,查看 API 交互文档如下,该接口将接收application/json
类型的参数。
FastAPI 支持同时定义 Path 参数、Query 参数和请求体参数,FastAPI 将会正确识别并获取数据。
参数在 url 中也声明了,它将被解释为 path 参数
参数是单一类型(例如int、float、str、bool等),它将被解释为 query 参数
参数类型为继承 Pydantic 模块的
BaseModel
类的数据模型类,则它将被解释为请求体参数
4、form表单
在 OAuth2 规范的一种使用方式(密码流)中,需要将用户名、密码作为表单字段发送,而不是 JSON。
FastAPI 可以使用Form组件来接收表单数据,需要先使用pip install python-multipart
命令进行安装。
pip install python-multipart
from fastapi import FastAPI, Formapp = FastAPI()@app.post("/regin")
def regin(username: str = Form(..., max_length=16, min_length=8, regex='[a-zA-Z]'),password: str = Form(..., max_length=16, min_length=8, regex='[0-9]')):print(f"username:{username},password:{password}")return {"username": username}
5、文件上传
from fastapi import FastAPI, File, UploadFile
from typing import Listapp = FastAPI()# file: bytes = File():适合小文件上传
@app.post("/files/")
async def create_file(file: bytes = File()):print("file:", file)return {"file_size": len(file)}@app.post("/multiFiles/")
async def create_files(files: List[bytes] = File()):return {"file_sizes": [len(file) for file in files]}# file: UploadFile:适合大文件上传@app.post("/uploadFile/")
async def create_upload_file(file: UploadFile):with open(f"{file.filename}", 'wb') as f:for chunk in iter(lambda: file.file.read(1024), b''):f.write(chunk)return {"filename": file.filename}@app.post("/multiUploadFiles/")
async def create_upload_files(files: List[UploadFile]):return {"filenames": [file.filename for file in files]}
6、request对象
有些情况下我们希望能直接访问Request对象。例如我们在路径操作函数中想获取客户端的IP地址,需要在函数中声明Request类型的参数,FastAPI 就会自动传递 Request 对象给这个参数,我们就可以获取到 Request 对象及其属性信息,例如 header、url、cookie、session 等。
from fastapi import Request@app.get("/items")
async def items(request: Request):return {"请求URL:": request.url,"请求ip:": request.client.host,"请求宿主:": request.headers.get("user-agent"),"cookies": request.cookies,}
7、请求静态文件
在 Web 开发中,需要请求很多静态资源文件(不是由服务器生成的文件),如 css/js 和图片文件等。
from fastapi.staticfiles import StaticFilesapp = FastAPI()
app.mount("/static",StaticFiles(directory="static"))
8、响应模型相关参数
(1)response_model
前面写的这么多路径函数最终 return 的都是自定义结构的字典,FastAPI 提供了 response_model 参数,声明 return 响应体的模型
# 路径操作
@app.post("/items/", response_model=Item)
# 路径函数
async def create_item(item: Item):...
response_model 是路径操作的参数,并不是路径函数的参数哦
FastAPI将使用response_model
进行以下操作:
- 将输出数据转换为response_model中声明的数据类型。
- 验证数据结构和类型
- 将输出数据限制为该model定义的
- 添加到OpenAPI中
- 在自动文档系统中使用。
你可以在任意的路径操作中使用 response_model
参数来声明用于响应的模型
案例:
- 注册功能
- 输入账号、密码、昵称、邮箱,注册成功后返回个人信息
from typing import Unionfrom fastapi import FastAPI
from pydantic import BaseModel, EmailStrapp = FastAPI()class UserIn(BaseModel):username: strpassword: stremail: EmailStrfull_name: Union[str, None] = Noneclass UserOut(BaseModel):username: stremail: EmailStrfull_name: Union[str, None] = None@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn):return user
(2)response_model_exclude_unset
通过上面的例子,我们学到了如何用response_model控制响应体结构,但是如果它们实际上没有存储,则可能要从结果中忽略它们。例如,如果model在NoSQL数据库中具有很多可选属性,但是不想发送很长的JSON响应,其中包含默认值。
案例:
from typing import List, Unionfrom fastapi import FastAPI
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: Union[str, None] = Noneprice: floattax: float = 10.5tags: List[str] = []items = {"foo": {"name": "Foo", "price": 50.2},"bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},"baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):return items[item_id]
不设置unset参数:
{"name": "Foo","description": null,"price": 50.2,"tax": 10.5,"tags": []
}
设置unset参数:
{"name": "Foo","price": 50.2
}
使用路径操作装饰器的 response_model
参数来定义响应模型,特别是确保私有数据被过滤掉。使用 response_model_exclude_unset
来仅返回显式设定的值。 除了response_model_exclude_unset
以外,还有response_model_exclude_defaults
和response_model_exclude_none
,我们可以很直观的了解到他们的意思,不返回是默认值的字段和不返回是None的字段。
(3)INCLUDE和EXCLUDE
# response_model_exclude
@app.get("/items/{item_id}", response_model=Item, response_model_exclude={"description"}, )
async def read_item(item_id: str):return items[item_id]# response_model_include
@app.get("/items/{item_id}", response_model=Item, response_model_include={"name", "price"}, )
async def read_item(item_id: str):return items[item_id]
五、jinja2模板
要了解jinja2,那么需要先理解模板的概念。模板在Python的web开发中⼴泛使⽤,它能够有效的将业务逻辑和页⾯逻辑分开,使代码可读性增强、并且更加容易理解和维护。 模板简单来说就是⼀个其中包涵占位变量表⽰动态的部分的⽂件,模板⽂件在经过动态赋值后,返回给⽤户。
jinja2是Flask作者开发的⼀个模板系统,起初是仿django模板的⼀个模板引擎,为Flask提供模板⽀持,由于其灵活,快速和安全等优点被⼴泛使⽤。
在jinja2中,存在三种语法:
- 变量取值 {{ }}
- 控制结构 {% %}
5.1、jinja2 的变量
Main.py
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
import uvicornapp = FastAPI() # 实例化 FastAPI对象
templates = Jinja2Templates(directory="templates") # 实例化Jinja2对象,并将文件夹路径设置为以templates命令的文件夹@app.get('/')
def hello(request: Request):return templates.TemplateResponse('index.html',{'request': request, # 注意,返回模板响应时,必须有request键值对,且值为Request请求对象'user': 'yuan',"books": ["金瓶梅", "聊斋", "剪灯新话", "国色天香"],"booksDict": {"金瓶梅": {"price": 100, "publish": "苹果出版社"},"聊斋": {"price": 200, "publish": "橘子出版社"},}})
if __name__ == '__main__':uvicorn.run("main:app", port=8080, debug=True, reload=True)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h1>{{ user}}</h1><p>{{ books.0 }}</p>
<p>{{ books.1 }}</p>
<p>{{ books.2 }}</p>
<p>{{ books.3 }}</p><p>{{ booksDict.金瓶梅.price }}</p></body>
</html>
5.2、jinja2 的过滤器
变量可以通过“过滤器”进⾏修改,过滤器可以理解为是jinja2⾥⾯的内置函数和字符串处理函数。常⽤的过滤器有:
过滤器名称 | 说明 |
---|---|
capitialize | 把值的⾸字母转换成⼤写,其他⼦母转换为⼩写 |
lower | 把值转换成⼩写形式 |
title | 把值中每个单词的⾸字母都转换成⼤写 |
trim | 把值的⾸尾空格去掉 |
striptags | 渲染之前把值中所有的HTML标签都删掉 |
join | 拼接多个值为字符串 |
round | 默认对数字进⾏四舍五⼊,也可以⽤参数进⾏控制 |
safe | 渲染时值不转义 |
那么如何使⽤这些过滤器呢?只需要在变量后⾯使⽤管道(|)分割,多个过滤器可以链式调⽤,前⼀个过滤器的输出会作为后⼀个过滤 器的输⼊。
{{ 'abc'| captialize }} # Abc{{ 'abc'| upper }} # ABC{{ 'hello world'| title }} # Hello World{{ "hello world"| replace('world','yuan') | upper }} # HELLO YUAN{{ 18.18 | round | int }} # 18
5.3、jinja2 的控制结构
5.3.1、分支控制
jinja2中的if语句类似与Python的if语句,它也具有单分⽀,多分⽀等多种结构,不同的是,条件语句不需要使⽤冒号结尾,⽽结束控制语句,需要使⽤endif关键字
{% if age > 18 %}<p>成年区</p>{% else %}<p>未成年区</p>{% endif %}
5.3.2、循环控制
jinja2中的for循环⽤于迭代Python的数据类型,包括列表,元组和字典。在jinja2中不存在while循环。
{% for book in books %}<p>{{ book }}</p>
{% endfor %}
六、ORM操作
在大型的web开发中,我们肯定会用到数据库操作,那么FastAPI也支持数据库的开发,你可以用 PostgreSQL、MySQL、 SQLite Oracle 等。本文用SQLite为例。我们看下在fastapi是如何操作设计数据库的。
fastapi是一个很优秀的框架,但是缺少一个合适的orm,官方代码里面使用的是sqlalchemy,Tortoise ORM 是受 Django 启发的易于使用的异步 ORM (对象关系映射器)。
Tortoise ORM 目前支持以下数据库:
- PostgreSQL >= 9.4(使用
asyncpg
)- SQLite(使用
aiosqlite
)- MySQL/MariaDB(使用
aiomysql
或使用asyncmy)
6.1、创建模型
models.py
from tortoise.models import Model
from tortoise import fieldsclass Clas(Model):name = fields.CharField(max_length=255, description='班级名称')class Teacher(Model):id = fields.IntField(pk=True)name = fields.CharField(max_length=255, description='姓名')tno = fields.IntField(description='账号')pwd = fields.CharField(max_length=255, description='密码')class Student(Model):id = fields.IntField(pk=True)sno = fields.IntField(description='学号')pwd = fields.CharField(max_length=255, description='密码')name = fields.CharField(max_length=255, description='姓名')# 一对多clas = fields.ForeignKeyField('models.Clas', related_name='students')# 多对多courses = fields.ManyToManyField('models.Course', related_name='students',description='学生选课表')class Course(Model):id = fields.IntField(pk=True)name = fields.CharField(max_length=255, description='课程名')teacher = fields.ForeignKeyField('models.Teacher', related_name='courses', description='课程讲师')
6.2、aerich迁移工具
main.py
import uvicorn
from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise
from settings import TORTOISE_ORMapp = 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='127.0.0.1', port=8000, reload=True,debug=True, workers=1)
settings.py
TORTOISE_ORM = {'connections': {'default': {# 'engine': 'tortoise.backends.asyncpg', PostgreSQL'engine': 'tortoise.backends.mysql', # MySQL or Mariadb'credentials': {'host': '127.0.0.1','port': '3306','user': 'root','password': 'yuan0316','database': 'fastapi','minsize': 1,'maxsize': 5,'charset': 'utf8mb4',"echo": True}},},'apps': {'models': {'models': ['apps.models', "aerich.models"],'default_connection': 'default',}},'use_tz': False,'timezone': 'Asia/Shanghai'
}
aerich
是一种ORM迁移工具,需要结合tortoise
异步orm框架使用。安装aerich
|
1. 初始化配置,只需要使用一次
|
初始化完会在当前目录生成一个文件:pyproject.toml和一个文件夹:migrations
pyproject.toml
:保存配置文件路径,低版本可能是aerich.ini
migrations
:存放迁移文件
2. 初始化数据库,一般情况下只用一次
|
此时数据库中就有相应的表格
如果
TORTOISE_ORM
配置文件中的models
改了名,则执行这条命令时需要增加--app
参数,来指定你修改的名字
3. 更新模型并进行迁移
修改model类,重新生成迁移文件,比如添加一个字段
|
|
迁移文件名的格式为 {version_num}{datetime}{name|update}.json。
注意,此时sql并没有执行,数据库中admin表中没有xxx字段
4. 重新执行迁移,写入数据库
| |
5. 回到上一个版本
| |
6. 查看历史迁移记录
| |
6.3、api接口与restful规范
1、api接口
应用程序编程接口(Application Programming Interface,API接口),就是应用程序对外提供了一个操作数据的入口,这个入口可以是一个函数或类方法,也可以是一个url地址或者一个网络地址。当客户端调用这个入口,应用程序则会执行对应代码操作,给客户端完成相对应的功能。
当然,api接口在工作中是比较常见的开发内容,有时候,我们会调用其他人编写的api接口,有时候,我们也需要提供api接口给其他人操作。由此就会带来一个问题,api接口往往都是一个函数、类方法、或者url或其他网络地址,不断是哪一种,当api接口编写过程中,我们都要考虑一个问题就是这个接口应该怎么编写?接口怎么写的更加容易维护和清晰,这就需要大家在调用或者编写api接口的时候要有一个明确的编写规范!!!
2、restful规范
为了在团队内部形成共识、防止个人习惯差异引起的混乱,我们都需要找到一种大家都觉得很好的接口实现规范,而且这种规范能够让后端写的接口,用途一目了然,减少客户端和服务端双方之间的合作成本。
目前市面上大部分公司开发人员使用的接口实现规范主要有:restful、RPC。
REST与技术无关,代表的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”或“表现层状态转化”。
简单来说,REST的含义就是客户端与Web服务器之间进行交互的时候,使用HTTP协议中的4个请求方法代表不同的动作。
GET用来获取资源
POST用来新建资源
PUT用来更新资源
DELETE用来删除资源。
只要API程序遵循了REST风格,那就可以称其为RESTful API。目前在前后端分离的架构中,前后端基本都是通过RESTful API来进行交互。
例如,我们现在要编写一个选课系统的接口,我们可以查询对一个学生进行查询、创建、更新和删除等操作,我们在编写程序的时候就要设计客户端浏览器与我们Web服务端交互的方式和路径。
而对于数据资源分别使用POST、DELETE、GET、UPDATE等请求动作来表达对数据的增删查改。
GET | /students | 获取所有学生 |
---|---|---|
请求方法 | 请求地址 | 后端操作 |
GET | /students | 获取所有学生 |
POST | /students | 增加学生 |
GET | /students/1 | 获取编号为1的学生 |
PUT | /students/1 | 修改编号为1的学生 |
DELETE | /students/1 | 删除编号为1的学生 |
api/student.py
from fastapi.exceptions import HTTPExceptionfrom models import *from pydantic import BaseModel
from typing import List, Union
from fastapi import APIRouterapi_student = APIRouter()@api_student.get("/student")
async def getAllStudent():students = await Student.all().values("name", "clas__name")# students = await Student.filter(name__icontains='a').values("name", "clas__name")# print("students", students)# for i in students:# print(i)## rain = await Student.get(name='rain')# print(rain, type(rain))# print(rain.sno)return studentsclass StudentModel(BaseModel):name: strpwd: strsno: intclas_id: Union[int, None] = Nonecourses: List[int] = []@api_student.post("/student")
async def addStudent(stu: StudentModel):# 添加数据库操作# 方式1# student = Student(name=stu.name, pwd=stu.pwd, sno=stu.sno, clas_id=stu.clas)# await student.save()# 方式2student = await Student.create(name=stu.name, pwd=stu.pwd, sno=stu.sno, clas_id=stu.clas_id)print(student, dir(student))# 添加多对多关系记录courses = await Course.filter(id__in=stu.courses)print("courses", courses)await student.courses.add(*courses)print("student", student.courses)return student@api_student.put("/student/{student_id}")
async def update_student(student_id: int, student: StudentModel):data = student.dict(exclude_unset=True)courses = data.pop("courses")print(data, courses)await Student.filter(id=student_id).update(**data)courses = await Course.filter(id__in=student.courses)edit_student = await Student.get(id=student_id)await edit_student.courses.clear()await edit_student.courses.add(*courses)return student@api_student.delete("/student/{student_id}")
async def delete_student(student_id: int):deleted_count = await Student.filter(id=student_id).delete() # 条件删除if not deleted_count:raise HTTPException(status_code=404, detail=f"Student {student_id} not found")return {}
七、中间件与CORS
7.1、中间件
你可以向 FastAPI 应用添加中间件.
“中间件"是一个函数,它在每个请求被特定的路径操作处理之前,以及在每个响应之后工作.
如果你使用了 yield
关键字依赖, 依赖中的退出代码将在执行中间件后执行.
如果有任何后台任务(稍后记录), 它们将在执行中间件后运行.
要创建中间件你可以在函数的顶部使用装饰器 @app.middleware("http")
.
中间件参数接收如下参数:
request
.- 一个函数
call_next
,它将接收request,作为参数.
- 这个函数将
request
传递给相应的 路径操作.- 然后它将返回由相应的路径操作生成的
response
.- 然后你可以在返回
response
前进一步修改它.
import uvicorn
from fastapi import FastAPIfrom fastapi import Request
from fastapi.responses import Response
import timeapp = FastAPI()@app.middleware("http")
async def m2(request: Request, call_next):# 请求代码块print("m2 request")response = await call_next(request)# 响应代码块response.headers["author"] = "yuan"print("m2 response")return response@app.middleware("http")
async def m1(request: Request, call_next):# 请求代码块print("m1 request")# if request.client.host in ["127.0.0.1", ]: # 黑名单# return Response(content="visit forbidden")# if request.url.path in ["/user"]:# return Response(content="visit forbidden")start = time.time()response = await call_next(request)# 响应代码块print("m1 response")end = time.time()response.headers["ProcessTimer"] = str(end - start)return response@app.get("/user")
def get_user():time.sleep(3)print("get_user函数执行")return {"user": "current user"}@app.get("/item/{item_id}")
def get_item(item_id: int):time.sleep(2)print("get_item函数执行")return {"item_id": item_id}if __name__ == '__main__':uvicorn.run('main:app', host='127.0.0.1', port=8030, reload=True,debug=True, workers=1)
7.2、CORS
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
</head>
<body><p>click</p><script>$("p").click(function () {$.ajax({url: "http://127.0.0.1:8080/",success: function (res) {$("p").html(res.message)},})})</script>
</body>
</html>
@app.middleware("http")
async def CORSMiddleware(request: Request, call_next):response = await call_next(request)print(response.headers)return response
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddlewareapp = FastAPI()
origins = ["http://localhost:63342"
]app.add_middleware(CORSMiddleware,allow_origins=origins, # *:代表所有客户端allow_credentials=True,allow_methods=["GET"],allow_headers=["*"],
)@app.get("/")
def main():return {"message": "Hello World"}if __name__ == '__main__':import uvicornuvicorn.run("main:app", host="127.0.0.1", port=8080, debug=True, reload=True)
参考文献:FastAPI框架 | YUAN
相关文章:
FastApi教程
FastAPI框架 fastapi,一个用于构建 API 的现代、快速(高性能)的web框架。 fastapi是建立在Starlette和Pydantic基础上的,Pydantic是一个基于Python类型提示来定义数据验证、序列化和文档的库。Starlette是一种轻量级的ASGI框架/…...
HTB:WifineticTwo[WriteUP]
目录 连接至HTB服务器并启动靶机 信息搜集 使用rustscan对靶机TCP端口进行开放扫描 使用nmap对靶机开放端口进行脚本、服务扫描 使用curl访问靶机8080端口 使用浏览器直接访问/login路径 漏洞利用 使用searchsploit搜索该WebAPP漏洞 Payload USER_FLAG:bb…...
ubuntu16.04在ros使用USB摄像头-解决could not open /dev/video0问题
首先检查摄像头 lsusb 安装 uvc camera 功能包 sudo apt-get install ros-indigo-uvc-camera 安装 image 相关功能包 sudo apt-get install ros-kinetic-image-* sudo apt-get install ros-kinetic-rqt-image-view运行 uvc_camera 节点 首先输入roscore 然后另外开一个终端输入…...
大模型专栏--什么是大模型
什么是大模型 来自 chatGPT 的回答: “大模型”通常指的是在机器学习和深度学习领域,尤其是自然语言处理(NLP)和计算机视觉(CV)中,具有大量参数和复杂结构的模型。这些模型通常需要大量的数据和…...
LLaMA-Mesh: Unifying 3D Mesh Generation with Language Models 论文解读
目录 一、概述 二、相关工作 1、LLMs到多模态 2、3D对象生成 3、自回归的Mesh生成 三、LLaMA-Mesh 1、3D表示 2、预训练模型 3、有监督的微调数据集 4、数据集演示 四、实验 1、生成的多样性 2、不同模型text-to-Mesh的比较 3、通用语境的评估 一、概述 该论文首…...
golang实现TCP服务器与客户端的断线自动重连功能
1.服务端 2.客户端 生成服务端口程序: 生成客户端程序: 测试断线重连: 初始连接成功...
项目实战:基于深度学习的人脸表情识别系统设计与实现
大家好,人脸表情识别是计算机视觉领域中的一个重要研究方向,它涉及到对人类情感状态的理解和分析。随着深度学习技术的发展,基于深度学习的人脸表情识别系统因其高精度和强大的特征学习能力而受到广泛关注。本文旨在探讨基于深度学习的人脸表…...
【mongodb】社区版8:改变配置bindip和授权
更改配置 sudo systemctl restart mongod (base) root@k8s-master-pfsrv:/home/zhangbin# sudo tail -n 20 /var/log/mongodb/mongod.log 日志感觉是成功了:{"t":{"$date":"2024-11-19T19:57:47.076+08:00"...
python入门9-函数基础
函数介绍 <1>什么是函数 请看如下代码: print(" _ooOoo_ ") print(" o8888888o ") print(" 88 . 88 ") print(" …...
AMD(Xilinx) FPGA配置Flash大小选择
目录 1 FPGA配置Flash大小的决定因素2 为什么选择的Flash容量大小为最小保证能够完成整个FPGA的配置呢? 1 FPGA配置Flash大小的决定因素 在进行FPGA硬件设计时,选择合适的配置Flash是我们进行硬件设计必须考虑的,那么配置Flash大小的选择由什…...
TypeScript学习笔记(二)
接一 四、类型声明 使用 : 来对变量或函数形参,进行类型声明: let a: string //变量a只能存储字符串 let b: number //变量b只能存储数值 let c: boolean //变量c只能存储布尔值 a hello a 100 //警告:不能将类型“number”分配给类型“…...
Centos Stream 9安装Jenkins-2.485 构建自动化项目步骤
官网:https://www.jenkins.io/ 1 下载 环境准备: 版本支持查询:https://pkg.jenkins.io/redhat-stable/ 安装JDK17:https://blog.csdn.net/qq_44870331/article/details/140784297 yum -y install epel-release wget upgradew…...
多目标粒子群优化(Multi-Objective Particle Swarm Optimization, MOPSO)算法
概述 多目标粒子群优化(MOPSO) 是粒子群优化(PSO)的一种扩展,用于解决具有多个目标函数的优化问题。MOPSO的目标是找到一组非支配解(Pareto最优解),这些解在不同目标之间达到平衡。…...
【网络系统管理】2023年全国职业院校技能大赛:组策略--10套题组合--1
1、限制访问C盘; (1)搜索《我的电脑》 (2)用户配置\策略\管理模板\Windows组件\文件资源管理器 2、禁止运行run.exe; (1)搜索《应用程序》 (2)用户配置\策略\管理模板\系统...
【Golang】——Gin 框架中的 API 请求处理与 JSON 数据绑定
在现代 Web 开发中,API(特别是 RESTful API)是前后端分离架构的核心。Gin 框架提供了丰富的功能来处理 API 请求和 JSON 数据,使得开发者可以快速构建高效的接口服务。本篇博客将从基础到深入,全面讲解如何使用 Gin 框…...
在Linux下配置gitee与Github的远程仓库
目录 前言 云服务器下载git 检测是否下载成功git Linux下配置gitee远程仓库 代码提交演示 git三板斧 Linux下配置Github远程仓库 最后的提醒 前言 那么本篇文章将是在,你已经创建了本地仓库的基础上,在Linux下配置gitee的远程仓库的步骤ÿ…...
自动化测试过程操作细节
一、软件与框架介绍 1. Postman 读音:[pəʊstmən](剖斯特曼) 介绍:API开发与测试的得力助手,通过直观界面发送HTTP请求,查看响应数据。支持环境变量、集合、脚本等功能。 主要特点:易于使用…...
iic协议
IIC(Inter-Integrated Circuit)协议,也被称为I2C协议,是一种由荷兰的PHILIPS公司(现为NXP半导体公司)开发的简单、高效的通信协议。以下是关于IIC协议的详细介绍: 一、IIC协议概述 定义&#…...
uniapp、js判断输入的内容是整数
清奇的思路 通过取余运算符 % 来检查 输入的内容是否为整数 for (var i 0; i < this.list.length; i) {if (this.list[i].times % 1 ! 0) { // 使用取余运算符检查是否为整数uni.showToast({icon: none,title: 请输入整数的套餐次数,})return;}}...
《Qt Creator:人工智能时代的跨平台开发利器》
《Qt Creator:人工智能时代的跨平台开发利器》 一、Qt Creator 简介(一)功能和优势(二)快捷键与效率提升(三)跨平台支持(四)工具介绍与使用主要特性:使用步骤…...
The Yarn application application_xxx_xxx doesn‘t exist in RM
本文主要解决flink在standalone模式下,flink run却一直使用yarn-session模式的问题。 问题 有个客户找到笔者,问题是报错如下: 分析 笔者先从环境入手,首先要确定的是flink是使用了什么模式。确认过后是使用standalone模式。 那就很奇怪&a…...
爬虫实战:采集知乎XXX话题数据
目录 反爬虫的本意和其带来的挑战目标实战开发准备代码开发发现问题1. 发现问题[01]2. 发现问题[02] 解决问题1. 解决问题[01]2. 解决问题[02] 最终结果 结语 反爬虫的本意和其带来的挑战 在这个数字化时代社交媒体已经成为人们表达观点的重要渠道,对企业来说&…...
【C++篇】像解谜一样转换字符串:stoi 带你走向整数的世界
文章目录 前言 在现代 C 编程中,字符串与数字之间的转换是非常常见的需求。随着编程语言的发展,C 提供了多种方式来处理这种转换。stoi(string to integer)函数正是为了简化这一任务而被引入的。 在 C 的早期版本中,字…...
小U数数问题
问题描述 小U正在数偶数,从 0,2,4,6,8,10,12,…0,2,4,6,8,10,12,… 开始,依次将这些数连在一起,形成一个无穷长的字符串,例如:"0246810121416..."。小U想知道这个字符串中的第 nn 个字符是什么。 测试样例 …...
Rocky Linux 系统安装/部署 Docker
1、下载docker-ce的repo文件 [rootlocalhost ~]# curl https://download.docker.com/linux/centos/docker-ce.repo -o /etc/yum.repos.d/docker.repo % Total % Received % Xferd Average Speed Time Time Time Current Dloa…...
程序语言语法上手题目合集
程序语言语法上手题目合集 1跑步2猜年龄3Vigenre 密码 1跑步 2.跑步 - 蓝桥云课 枚举日期,判断是否符合条件即可。 参考程序: #include<stdio.h> int y2022,m1,d1; int week6; int month[13]{0,31,28,31,30,31,30,31,31,30,31,30,31};int judg…...
MCU通过APB总线与FPGA 数据交互(实现JATG 模块的控制)
问题出发点: 通过MCU 的APB 将数据发送到fpga 端;fpga 端实现 jtag 模块功能,支持状态机TAP的移动主要是:从IDLE 移动到 shirft-IR 发送指令数据然后再回到 IDLE ,从 IDLE 移动到shirft-DR 发送用户数据再回到IDLE;从而可以 通过 mcu端实现jtag 协议控制。 为了实现 MC…...
Mysql的UPDATE(更新数据)详解
MySQL的UPDATE语句是用于修改数据库表中已存在的记录,本文将详细介绍UPDATE语句的基本语法、高级用法、性能优化策略以及注意事项,帮助您更好地理解和应用这一重要的SQL命令。 1. 基本语法 单表更新 单表更新的基本语法如下: UPDATE [LOW…...
【AI最前线】DP双像素sensor相关的AI算法全集:深度估计、图像去模糊去雨去雾恢复、图像重建、自动对焦
Dual Pixel 简介 双像素是成像系统的感光元器件中单帧同时生成的图像:通过双像素可以实现:深度估计、图像去模糊去雨去雾恢复、图像重建 成像原理来源如上,也有遮罩等方式的pd生成,如图双像素视图可以看到光圈的不同一半&#x…...
如何使用AWS Lambda构建一个云端工具(超详细)
首发地址(欢迎大家访问):如何使用AWS Lambda构建一个云端工具(超详细) 1 前言 1.1 无服务器架构 无服务器架构(Serverless Computing)是一种云计算服务模型,它允许开发者构建和运行…...
Scala—数组(数组定义、数组常用方法等)— 用法详解
Scala Scala-数组-用法详解 Scala一、数组的定义1. new 关键字2. Array 对象的 apply 方法3. 创建多维数组 二、数组常用方法1. length:获取数组的长度。2. apply:通过索引获取数组中的元素。3. update:通过索引更新数组中的元素。4. foreach…...
使用 Elastic 收集 Windows 遥测数据:ETW Filebeat 输入简介
作者:来自 Elastic Chema Martinez 在安全领域,能够使用 Windows 主机的系统遥测数据为监控、故障排除和保护 IT 环境开辟了新的可能性。意识到这一点,Elastic 推出了专注于 Windows 事件跟踪 (ETW) 的新功能 - 这是一种强大的 Windows 原生机…...
二分排序
二分问题之前遇到很多次了,不过一直是手写完整二分,现在转变一下想法,直接使用函数lower_bound和upper_bound更方便 lower_bound 有序数组中 查找第一个不小于指定值的位置。 本质二分代码: int lower_bound_custom(int* arr, i…...
数据库---HSQLDB使用教程详解
本学校期末的课程设计要求使用HSQLDB数据库,作为一个小众且轻量的数据库,很少人接触过,再加上同学们都问这个方面,所以就出教程,展示怎么使用HSQLDB。 第一步:启动HSQLDB 下载HSQLDB的jar包,因…...
Makefile基础应用
1 使用场景 在Linux环境下,我们通常需要通过命令行来编译代码。例如,在使用gcc编译C语言代码时,需要使用以下命令。 gcc -o main main.c 使用这种方式编译代码非常吃力,每次调试代码都需要重新在命令行下重新编译,重复…...
一个点绕任意点旋转后的点的坐标
在平面坐标上,任意点P(x1,y1),绕一个坐标点Q(x2,y2)逆时针旋转θ角度后,新的坐标设为(x, y)的计算公式: x (x1 - x2)*cos(θ) - (y1 - y2)*sin(θ) x2 ; y (x1 - x2)*sin(θ) (y1 - y2)*cos(θ) y2 ; 另一个场景应用,坐标轴绕…...
嵌入式硬件杂谈(二)-芯片输入接入0.1uf电容的本质(退耦电容)
引言:对于嵌入式硬件这个庞大的知识体系而言,太多离散的知识点很容易疏漏,因此对于这些容易忘记甚至不明白的知识点做成一个梳理,供大家参考以及学习,本文主要针对芯片输入接入0.1uf电容的本质的知识点的进行学习。 目…...
算力100问☞第16问:什么是TPU?
TPU全称是Tensor Processing Unit芯片,中文全称是张量处理单元芯片,是谷歌开发的一种特殊类型的芯片,用于加速人工智能(AI)和机器学习(ML)工作负载。TPU主要针对张量(tensor…...
Level DB --- SkipList
class SkipList class SkipList 是Level DB中的重要数据结构,存储在memtable中的数据通过SkipList来存储和检索数据,它有优秀的读写性能,且和红黑树相比,更适合多线程的操作。 SkipList SkipList还是一个比较简单的数据结构&a…...
全面解析 JMeter 后置处理器:概念、工作原理与应用场景
在性能测试中,Apache JMeter是一个非常流行的工具,它不仅能够模拟大量用户进行并发访问,还提供了丰富的扩展机制来满足各种复杂的测试需求。后置处理器(Post-Processor)是JMeter中非常重要的组件之一,用于在…...
【视频】二维码识别:libzbar-dev、zbar-tools(zbarimg )
1、简介 ZBar可以使用多个方式识别各种条形码和二维码。 支持的格式有:EAN-13/UPC-A、UPC-E、EAN-8、Code 128、Code 93、Code 39、Codabar、Interleaved 2 of 5、QR Code和SQ Code 支持的来源有:视频流、图像文件等 libzbar-dev:二维码识别开发库 zbar-tools(zbarimg …...
EasyExcel: 结合springboot实现表格导出入(单/多sheet), 全字段校验,批次等操作(全)
全文目录,一步到位 1.前言简介1.1 链接传送门1.1.1 easyExcel传送门 2. Excel表格导入过程2.1 easyExcel的使用准备工作2.1.1 导入maven依赖2.1.2 建立一个util包2.1.3 ExcelUtils统一功能封装(单/多sheet导入)2.1.4 ExcelDataListener数据监听器2.1.5 ResponseHelper响应值处理…...
志愿者小程序源码社区网格志愿者服务小程序php
志愿者服务小程序源码开发方案:开发语言后端php,tp框架,前端是uniapp。 一 志愿者端-小程序: 申请成为志愿者,志愿者组织端进行审核。成为志愿者后,可以报名参加志愿者活动。 志愿者地图:可以…...
HTML实现 扫雷游戏
前言: 游戏起源与发展 扫雷游戏的雏形可追溯到 1973 年的 “方块(cube)” 游戏,后经改编出现了 “rlogic” 游戏,玩家需为指挥中心探出安全路线避开地雷。在此基础上,开发者汤姆・安德森编写出了扫雷游戏的…...
小白学多线程(持续更新中)
1.JDK中的线程池 JDK中创建线程池有一个最全的构造方法,里面七个参数如上所示。 执行流程分析: 模拟条件:10个核心线程数,200个最大线程数,阻塞队列大小为100。 当有小于十个任务要处理时,因为小于核心线…...
【uni-app多端】修复stmopjs下plus-websocket无心跳的问题
从这篇文章接着向下看: uniapp plus-websocket 和stompjs连接教程 安卓ios手机端有效 - 简书 按照文章的方式,能够实现APP下stmopjs长连接。但是有一个问题,就是会频繁输出 res-创建连接-1- 跟踪连接,会发现连接都会在大约40s后…...
【SLAM文献阅读】基于概率模型的视觉SLAM动态检测与数据关联方法
A dynamic detection and data association method based on probabilistic models for visual SLAM 《基于概率模型的视觉SLAM动态检测与数据关联方法》 2024 摘要: 通常,静态特征采用多视图几何来估计相机姿态和重建环境地图。因此,动态特…...
Linux系统使用valgrind分析C++程序内存资源使用情况
内存占用是我们开发的时候需要重点关注的一个问题,我们可以人工根据代码推理出一个消耗内存较大的函数,也可以推理出大概会消耗多少内存,但是这种方法不仅麻烦,而且得到的只是推理的数据,而不是实际的数据。 我们可以…...
Selenium+Java(19):使用IDEA的Selenium插件辅助超快速编写Pages
前言 或是惊叹于Selenium对于IDEA的支持已经达到了这样的地步,又或是由于这个好用的小工具的入口就在那里,它已经陪伴了我这么久,而我这么久的时间却都没有发现它。在突然发现这个功能的一瞬间,真的是喜悦感爆棚,于是赶快写下了这篇文章。希望可以帮助到其他同样在做UI自动…...
Unity 设计模式-单例模式(Singleton)详解
设计模式 设计模式 是指在软件开发中为解决常见问题而总结出的一套 可复用的解决方案。这些模式是经过长期实践证明有效的 编程经验总结,并可以在不同的项目中复用。设计模式并不是代码片段,而是对常见问题的 抽象解决方案,它提供了代码结构…...