一、基本要求:
1.python版本3.6+支持异步编程与类型提示 type hints
2. http基础了解(get/post/put/delete)、状态码、请求协议等
3.推荐使用python虚拟环境进行开发环境隔离
python -m venv myenv
source myenv/bin/activate # Linux/Mac
myenv\Scripts\activate # Windows
4.了解fastapi最重要的两个插件:Pydantic和Starlette。
Pydantic是基于Python类型提示定义数据验证、序列化和文档库
Starlette是一种轻量级的ASGI框架,是构建高性能Asyncio服务的理想选择。
二、创建项目:
1.mkdir创建目FastApiDemo
在目录下创建虚拟环境myenv执行命令如下:
python3 -m venv myenv
之后创建项目目录mkdir demo1:
得到如下的目录结构:
我这里使用的vscode开发环境:
Ctrl+shift +p 输入python解释器选择同级目录下的myenv环境。
之后在终端执行命令后进入虚拟环境,之后安装所需的插件等。
source myenv/bin/activate
2安装常用依赖库:
常用依赖库
FastAPI框架常用的主要依赖库如下:
❑email.validator:主要用于邮件格式校验处理。
❑requests:使用单例测试TestClient或请求第三方接口时需要使用该
依赖库。
❑aiofiles:主要用于异步处理文件读写操作。❑jinja2:主要供用户渲染静态文件模板时使用,当项目要使用后端渲
染模板时安装该依赖库。
❑Python-multipart:当需要获取From表单数据时,只有通过这个库才
可以提取表单的数据并进行解析。
❑itsdangerous:用于在SessionMiddleware中间件中生成Session临时
身份令牌。
❑graphene:需要GraphQLApp支持时安装这个依赖库。
❑orjson:主要用于JSON序列化和反序列化,如使用FastAPI提供的
ORJSONR-esponse响应体处理时,则需要安装这个依赖库。
❑ujson:主要用于JSON序列化和反序列化,如需要使用FastAPI提供
的UJSONResponse响应体时就需要安装该依赖库。
❑uvicorn:主要用于运行和加载服务应用程序Web服务
单独安装:
pip install fastapi
pip install "uvicorn[standard]" #此命令的主要功能是借助 Python 的包管理工具
#pip
来安装 Uvicorn 服务器,并且会额外安装# Uvicorn 的标准依赖项
全部安装的方法:
pip install fastapi[all]
创建如下的项目目录结构:
结构介绍:
根目录下main.py是主程序入口,flask_app.py是flask web架构的程序
apps目录下是各个应用程序,现有的代码结构如下各个app代码基本相同。
举例app01:
models.py是模型代码,urls.py实现路由和视图函数(类似Django的路由函数和视图函数)
一下是部分源码:
main.py:
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from fastapi.params import Path,Query
from fastapi.middleware.wsgi import WSGIMiddleware
from flask_app import flask_app
from apps.app01.urls import shop
from apps.app02.urls import user
from apps.app03.app03 import appo3
app = FastAPI(title='主应用',description='我是主应用文档的描述',version='v1.0.0')
#此处实现多应用挂载
app.mount('/flask',app=WSGIMiddleware(app=flask_app),name='flask_app')
#实现路由功能
app.include_router(shop,prefix='/shop',tags=['购物中心'])
app.include_router(user,prefix='/user',tags=['用户中心'])
app.include_router(appo3,prefix='/appo3',tags=['请求体数据'])
@app.get('/index',summary='首页')
async def index():
return JSONResponse(content={'code':200,'msg':'我是属于FastAPI的接口'})
@app.get('/param/{user_id}/book/{book_name}')
async def get_book_info(user_id: int=Path(...,description='用户ID'),book_name: str=Path(...,
description='书名',min_length=1,max_length=128),date: int=Query(...,description='日期'),version: int=Query(None,description='版本号')):
return JSONResponse(content={'code':200,'msg':'我是属于FastAPI的接口','user_id':user_id,'book_name':book_name,'date':date,'version':version})
部分代码介绍:
app.mount('/flask',app=WSGIMiddleware(app=flask_app),name='flask_app')
实现子应用挂载即可以是fastapi应用作子应用也可以挂载其他WSGI应用,此处挂载的是flask应用。
重点介绍路径参数和输入参数:
其中,@app.get()表示API端点的路径操作,也就是API装饰器,它里
面的传输参数则可以理解为路径操作参数;async def get_book_info()(忽略截图函数名的错误)表示
视图函数,该视图函数可以是同步函数,也可以是协程函数,其中需
要传入的参数表示路径函数参数,这里称其为视图函数参数
在上面的参数中:{user_id}和{book_name}两个路径参数变量,
FastAPI会自动把这两个参数传递到视图函数上。在视图函数中,对这
两个路径参数的要求如下:
user_id:int类型,是必填项。如果传递过程中没有这个参数,则会
抛出请求参数校验异常。
...:表示user_id是一个必填项
title:表示参数显示在API交互式文档中的标题名称。
description:表示参数显示在API交互式文档中的详细描述。
ge=10000:表示参数传值需要大于或等于10000,若不满足,则会
抛出请求参数校验异常
book_name:字符串类型,是必填项。如果传递过程中没有这个参数,
则会抛出请求参数校验异常。
min_length=1:表示参数传值需要满足字符串长度大于1,若不符合
该条件,则会抛出请求参数校验异常。
max_length=128:表示参数传值需要满足字符串长度小于50,若不
符合该条件,则会抛出请求参数校验异常
ps:在视图函数中,声明的参数分为有默认值和无默认值两种。如果把有
默认值参数放在无默认值参数的前面,那么IDE会提示告警,并且无法
启动服务。如果坚持把有默认值的参数放在最前面,则需要在第一个
参数前面加一个*
Query(查询)参数不属于路径参数的范畴,但是它会在URL地址上显
示出来,如http://127.0.0.1:8000/items/?skip=0&limit=10,其中,
skip=0&limit就是所谓的查询参数
参数多条件校验
和Path参数一样,FastAPI框架还提供了一个专门用于在查询参数中进
行多维度条件限制的Query类
Query类中的参数和Path中的大部分参数是相同的,所以这里不再重复
说明。这里需要关注user_id字段,该字段在对int类型数据校验时涉及
的参数说明如下:
❑gt:表示大于。
❑lt:表示小于。
❑ge:表示大于或等于。
❑le:表示小于或等于
Body参数
Body(请求体)参数表示在HTTP中提交请求体的数据,它既可以是某
种文档类型的数据,也可以是文件类型或是表单类的数据。常见的请
求体参数传递都是JSON格式的,如果是JSON格式的数据,则通常要求
提交请求头字段Content-Type的格式为如下形式。
FastAPI框架提供了如下3种方式来接收Body参数,并自动把JSON格式
的字符串转换为dict格式。
❑引入Pydantic模型来声明请求体并进行绑定
❑直接通过Request对象获取Body的函数。
❑使用Body类来定义
UploadFile方式接收文件上传
上文示例中,直接使用File对象来接收处理上传的文件,但它接收的是
字节数据,而且缺少相关文件元数据信息,如文件名称、文件大小、
文件格式类型等。如果需要获取更多关于文件的元信息,则需要从请
求头来截取。FastAPI框架提供了一个更高级的UploadFile类来处理类似
需求
flask_app.py代码如下:
from flask import Flask
from fastapi.middleware.wsgi import WSGIMiddleware
flask_app = Flask(__name__)
@flask_app.route('/index')
def flask_main():
return {'index':'我是flask的接口'}
apps/app01/urls.py代码如下:
from fastapi import APIRouter
shop = APIRouter()
@shop.get('/book')
async def get_book():
return {'code':200,'msg':'我是属于FastAPI shop app的接口'}
apps/app01/models.py代码如下:
from tortoise.models import Model
from tortoise import fields
class Students(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=64,description='姓名')
pwd = fields.CharField(max_length=64,description='密码')
sex = fields.CharField(max_length=16,description='性别')
number = fields.CharField(max_length=64,description='学号')
# 一对多的关系
clas = fields.ForeignKeyField('models.Clas',related_name='students')
#多对多的关系
course = fields.ManyToManyField('models.Course',related_name='students')
class Course(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=64,description='课程名称')
teacher = fields.ForeignKeyField('models.Teacher',related_name='course')
class Clas(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=64,description='班级名称')
class Teacher(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=64,description='老师名称')
pwd = fields.CharField(max_length=64,description='密码')
sex = fields.CharField(max_length=16,description='性别')
number = fields.CharField(max_length=64,description='工号')
三、静态文件和动态模板文件
request请求可能会请求静态html和一些动态数据的html(正常应该前后端分类,但是一些项目需要后端也实现前端的一些)
在根目录(在main.py同级)创建静态文件夹statics和模板文件夹templates。
在两个目录分别创建需要的文件(html,txt,图片等)细节不做介绍
在main.py下如何引用静态文件和动态模板做一些介绍:
from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from fastapi.responses import HTMLResponse
from fastapi import Request
import pathlib
import uvicorn
from tortoise.contrib.fastapi import register_tortoise
from settings import TORTOISE_ORM
app = FastAPI()
templates = Jinja2Templates(directory=f'{pathlib.Path.cwd()}/templates/')
staticfiles = StaticFiles(directory=f'{pathlib.Path.cwd()}/static/')
app.mount('/static',staticfiles,name='static')
register_tortoise(
app,
config = TORTOISE_ORM
)
@app.get("/",response_class=HTMLResponse)
async def get_response(request:Request):
return templates.TemplateResponse('index.html',{'request':request})
if __name__ == '__main__':
uvicorn.run(app = 'main:app',host='127.0.0.1',port=8000,reload=True,workers=1)
四、FastAPI的ORM模型
1.ORM模型是操作数据库的
ORM是对SQL语句的一种封装,它是对数据库表中列和行操
作的一种对象映射。在某些情况下,使用ORM库时甚至不需要了解
SQL,只需要通过对表映射出来的实体类模型进行操作就可实现对数
据的增、删、改、查操作
引入ORM库有以下几个好处:
❑对数据进行增、删、改、查更快捷。
❑有效避免编写SQL语句时以字符串拼接或字符串格式化的方式进行
入参的传输,进而规避SQL注入问题。
❑可以自适应且高效地切换到其他DBMS
(DataBase Management System),不需要额外修改逻辑,提高代
码的可移植性和跨平台兼容性
2.tortoise ORM支持的数据库:
1.PostgreSQL >=9.4 version (使用asyncpg)
2.SQLite (使用aiosqlite)
3.mysql/MariaDB (使用aiomysql或使用asyncmy)
安装tortoise ORM
pip install tortoise-orm
这里使用的是mysql所以需要安装异步支持(aiomysql)
pip install aiomysql
# 数据库迁移工具(推荐) pip install aerich
main.py
from fastapi import FastAPI
import uvicorn
from tortoise.contrib.fastapi import register_tortoise
from settings import TORTOISE_ORM
app = FastAPI()
register_tortoise(
app,
config = TORTOISE_ORM
)
if __name__ == '__main__':
uvicorn.run(app = 'main:app',host='127.0.0.1',port=8000,reload=True,workers=1)
settings.py和main.py放在同级目录,独立配置文件中初始化 Tortoise
TORTOISE_ORM={
'connections':{
'default':{
'engine': 'tortoise.backends.mysql',
'credentials':{
'host':'127.0.0.1',
'port':3306,
'user':'root',
'password':'jlcao',
'database':'fastapi_demo',
'minsize':1,
'maxsize':5,
'charset':'utf8mb4',
'echo':True
}
}
},
'apps':{
'models':{
'models':['app01.models','aerich.models'],
'default_connection':'default',
}
},
'use_tz':False,
'timezone':'Asia/Shanghai'
}
定义models.py的代码
from tortoise.models import Model
from tortoise import fields
class Students(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=64,description='姓名')
pwd = fields.CharField(max_length=64,description='密码')
sex = fields.CharField(max_length=16,description='性别')
number = fields.CharField(max_length=64,description='学号')
# 一对多的关系
clas = fields.ForeignKeyField('models.Clas',related_name='students')
#多对多的关系
course = fields.ManyToManyField('models.Course',related_name='students')
class Course(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=64,description='课程名称')
teacher = fields.ForeignKeyField('models.Teacher',related_name='course')
class Clas(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=64,description='班级名称')
class Teacher(Model):
id = fields.IntField(pk=True)
name = fields.CharField(max_length=64,description='老师名称')
pwd = fields.CharField(max_length=64,description='密码')
sex = fields.CharField(max_length=16,description='性别')
number = fields.CharField(max_length=64,description='工号')
使用 Aerich 进行数据库迁移
初始化迁移环境,终端执行
aerich init -t settings.TORTOISE_ORM # 指定配置文件中的 ORM 配置 aerich init-db # 生成初始迁移文件
以上操作后会生成操作的记录文件,在migrations目录下
from tortoise import BaseDBAsyncClient
async def upgrade(db: BaseDBAsyncClient) -> str:
return """
CREATE TABLE IF NOT EXISTS `clas` (
`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(64) NOT NULL COMMENT '班级名称'
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `students` (
`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(64) NOT NULL COMMENT '姓名',
`pwd` VARCHAR(64) NOT NULL COMMENT '密码',
`sex` VARCHAR(16) NOT NULL COMMENT '性别',
`number` VARCHAR(64) NOT NULL COMMENT '学号',
`clas_id` INT NOT NULL,
CONSTRAINT `fk_students_clas_822af58b` FOREIGN KEY (`clas_id`) REFERENCES `clas` (`id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `teacher` (
`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(64) NOT NULL COMMENT '老师名称',
`pwd` VARCHAR(64) NOT NULL COMMENT '密码',
`sex` VARCHAR(16) NOT NULL COMMENT '性别',
`number` VARCHAR(64) NOT NULL COMMENT '工号'
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `course` (
`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(64) NOT NULL COMMENT '课程名称',
`teacher_id` INT NOT NULL,
CONSTRAINT `fk_course_teacher_2de38fe7` FOREIGN KEY (`teacher_id`) REFERENCES `teacher` (`id`) ON DELETE CASCADE
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `aerich` (
`id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`version` VARCHAR(255) NOT NULL,
`app` VARCHAR(100) NOT NULL,
`content` JSON NOT NULL
) CHARACTER SET utf8mb4;
CREATE TABLE IF NOT EXISTS `students_course` (
`students_id` INT NOT NULL,
`course_id` INT NOT NULL,
FOREIGN KEY (`students_id`) REFERENCES `students` (`id`) ON DELETE CASCADE,
FOREIGN KEY (`course_id`) REFERENCES `course` (`id`) ON DELETE CASCADE,
UNIQUE KEY `uidx_students_co_student_cea02e` (`students_id`, `course_id`)
) CHARACTER SET utf8mb4;"""
async def downgrade(db: BaseDBAsyncClient) -> str:
return """
"""
数据模型变更后:
aerich migrate --name "add_user_table" # 生成迁移文件 aerich upgrade # 应用迁移到数据库
回滚上一个版本:
aerich history # 查看迁移历史 aerich downgrade # 回滚到上一个版本
关键插件说明
-
Tortoise-ORM
-
异步 ORM 框架,支持 PostgreSQL/MySQL/SQLite。
-
提供 Django-like 的模型定义和查询 API。
-
-
Aerich
-
数据库迁移工具,类似 Django 的
migrate
。 -
自动生成并管理数据库版本变更。
-
-
asyncpg/aiosqlite
-
异步数据库驱动,提升 FastAPI 的并发性能。
-
-
tortoise.contrib.pydantic
-
自动将 Tortoise 模型转换为 Pydantic 模型,简化数据验证。
-