fastapi——快速入门笔记
根据慕课网视频教程
地址:https://www.bilibili.com/video/BV1iN411X72b?p=36
print("\033[31m5. --- ORM模型: 从类创建符合的ORM对象模型 ---\033[Om")#显示彩色内容
fastapi是高性能的web框架。他的主要特点是:
快速编码
减少人为bug
直观
简易
具有交互式文档
基于API的开放标准(并与之完全兼容):OpenAPI(以前称为Swagger)和JSON Schema。
1.1fastapi的安装
一、fastapi的安装
pip install fastapi
当然你可以使用国内阿里云镜像源进行安装,会快很多,上面的语句变成下面的:
pip install fastapi -i https://mirrors.aliyun.com/pypi/simple
因为fastapi启动依赖于uvicorn,所以我们还需要安装uvicorn
pip install uvicorn -i https://mirrors.aliyun.com/pypi/simple
到这里,fastapi就安装完毕了,下面我们来验证一下安装是否成功
1-2、验证是否安装成功
新建名字叫main.py的文件,将下面内容复制到里面去
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
然后使用终端开启uvicorn
服务
uvicorn main:app --reload
uvicorn main:app 命令指:
main: main.py 文件(也可理解为Python模块).
app: main.py 中app = FastAPI()语句创建的app对象.
--reload: 在代码改变后重启服务器,只能在开发的时候使用
你将会看到如下的输出:
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [8438] using statreload
INFO: Started server process [8440]
INFO: Waiting for application startup.
INFO: Application startup complete.
然后打开浏览器,输入: http://127.0.0.1:8000。看看有没有打印出:"message": "Hello World"
这句话,如果有,表示安装成功。
如果你此时访问 http://127.0.0.1:8000/docs。你将会看到自动生成的API交互文档。这点很重要,也是fastapi的一个优点。
1.2.2fastapi项目启动时,提示ERROR
fastapi项目启动时,提示ERROR: Error loading ASGI app. Could not import module “main”.
文件名为 f1.py
代码如下:
from fastapi import FastAPI # 导入FastAPI
import uvicorn
app = FastAPI() # 创建一个app实例
@app.get("/") # 编写一个路径操作装饰器
async def root(): # 编写一个路径操作函数
return {
"你好!": "朋友。"}
if __name__ == '__main__':
uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)
注意:声明app的文件路径应该是 f1:app,而不是main:app。
只需将 app=‘main:app’ 改为app='f1:app’即可。
结束!
1.3fastapi固定开头
# -*- codeing = utf-8 -*-
# @time : 2021/5/7 23:57
# @file : main.py.PY
# @Author : 夜羽
from fastapi import FastAPI # 导入FastAPI
#from fastapi import APIRouter #接口路由
import uvicorn # 运行fastapi
'''内容选填
app = FastAPI() # 创建一个app实例
#app01 = APIRouter()
@app.get("/") # 编写一个路径操作装饰器
async def root(): # 编写一个路径操作函数
return {"你好!": "朋友。123"}
'''
if __name__ == '__main__':
uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True, workers=1)
# workers=1进程数量
main: main.py 文件(也可理解为Python模块).
app: main.py 中app = FastAPI()语句创建的app对象.
--reload: 在代码改变后重启服务器,只能在开发的时候使用
debug: 修改代码后不必再运行一次程序,保存后可直接运行
另一种方法
导入运行文件名在一个程序文件中:
from .chapter03 import app03
from .chapter04 import app04
from .chapter05 import app05
from .文件名 import app实例名
后只用一个程序运行多个:
from fastapi import FastAPI
import uvicorn #运行fastapi
from fastapi知识点教程 import app03 导入app实例名称项目
from fastapi知识点教程 import app04
from fastapi知识点教程 import app05
#from 上层文件夹名称 import app实例名
app = FastAPI()
#prefix= 路径 tags=[] 名称
app.include_router(app03, prefix='/chapter03', tags=['第三章 请求参数和验证'])
app.include_router(app04, prefix='/chapter04', tags=['第四章 响应处理和fastapi设置'])
app.include_router(app05, prefix='/chapter05', tags=['第五章 fastapi的依赖注入系统'])
if __name__ == '__main__':
uvicorn.run('RUN:app', host="127.0.0.1", port=8000, reload=True, debug=True, workers=1)
#woker=1进程数量
1.4代码练习
from typing import List, Optional #Optional 参数可以为空或已经声明的类型
app = FastAPI() # 创建一个app实例
class Cityinfo(BaseModel):
province: str
country: str
is_affectse: Optional[bool] = None
@app.get("/") # 编写一个路径操作装饰器
def root(): # 编写一个路径操作函数
return {
"你好!": "朋友。23"}
#@app.get("/city/{city}?q=xx") # 编写一个路径操作装饰器 q=xx 查询参数
@app.get("/city/{city}")
async def result(city: str,query: Optional[str] = None): # 编写一个路径操作函数
return {
"city": city, "query": query}
if __name__ == '__main__':
uvicorn.run(app='web1:app', host="127.0.0.1", port=8000, reload=True, debug=True)
# -*- codeing = utf-8 -*-
# @time : 2021/5/6 22:55
# @file : pydantic.PY
# @Author : 夜羽
# @Software : PyCharm
#导入库时一定要注意大小写
from pydantic import BaseModel, ValidationError #可在运行时提供代码类型提示,报错是提供较为友好的错误提示
from datetime import datetime, date
from pathlib import Path #新建Path文件
from typing import List, Optional #Optional 参数可以为空或已经声明的类型
from sqlalchemy import Column, Integer, String #列,征型,字符类型
from sqlalchemy.dialects.postgresql import array #元祖
from sqlalchemy.ext.declarative import declarative_base #声明
class user(BaseModel):
id: int
name: str = "john snow" #默认值
signup_ts: Optional[datetime] = None #Optional 参数可以为空或已经声明的类型
friends: list[int] = [] #列表中元素是int类型或者是可以直接转化为int 类型的值
date = {
"id" : "123456",
"name" : 'nima',
"signup_ts" : datetime.today(),#现在的时间
"friends" :[1,'2',3]
}
user = user(**date) # **的作用是收集关键字参数到一个新的字典,并将整个字典赋值给字典_date
print(user.id,user.name) #实例化后调用属性
print(user.json()) #字典形式打开
print(user.id) #实例化后调用属性
print(user.dict()) #字典形式打开
print(user.schema())
print(user.schema_json()) #会提示使用的数据格式类型
print(user.__fields__.keys()) #查看定义的类型,所有的字段都表明类就不会乱
"""
Path = Path('pydanti.json') #新建一个jsom文件
Path.write_text('{"id" : "123456","name" : "nima","signup_ts" : datetime.today(),friends" :[1,"2",3]}')
print(user.parse_file(Path)) #解析文件 parse_解析
#写入内容 write_text写入
#现在的时间"
User_data = {'{"id" : "123","name" : "nima","signup_ts" : datetime.today(),friends" :[1,"2",3]}'}
print(user.construct(**User_data))
"""
class sound(BaseModel):
sound: str
class dog(BaseModel):
birthday: Optional[datetime] = None
weight: float = Optional[None]
sound: List[sound] # 不同的叫声. 递归模型,就是指一个嵌套一个
dogs = dog(birthday=datetime.today(), weight=6.66, sound=[{
"sound": "wangwagn"}, {
"sound": "yingying"}])
print(dogs.dict())
print("\033[31m5. --- ORM模型: 从类创建符合的ORM对象模型 ---\033[Om")
Base = declarative_base() #声明性基础
class companyorm(Base):
from fastapi import APIRouter, Path #APIRouter api路由器, Path 路径校验
from enum import Enum # 枚举
app03 = APIRouter()
@app03.get("/path/parametrs")
def path01():
return {
"message": "this is a message"}
@app03.get("/path/{parametrs}") # 函数的顺序就是路由的顺序
def path01(parametrs: str):
return {
"message": parametrs}
class cityname(str,Enum): #枚举参数类型, 使用后可以选填下方参数
beijing = "beijing China"
shanghai = "shanghai China"
@app03.get("/enum/{city}") #枚举参数类型
async def latest(city: cityname):
if city == cityname.shanghai:
return {
'city_name': city, "确诊数量": 123, "死亡": 0}
if city == cityname.beijing:
return {
'city_name': city, "确诊数量": 1231, "死亡": 0}
return {
"city_name": city, "latest": "unknown"}
@app03.get("/files/{flie_path: path}") # 路径参数path parameters传递文件路径
def fliepath(flie_path: str):
return f"the file path is {flie_path}" #传递数据
# Path(None) 可为空 ,title="这是一个标题", description="描述", ge=1,le=10 大于1小于10
@app03.get("/path_1/{unm}")
def path03(
#num: int =Path(None, title="这是一个标题", description="描述",ge=1,le=10)
unm: int = Path(..., title="这是一个标题", description="描述", ge=1, le=10)
):
return unm
run运行文件
# -*- coding = utf-8 -*-
# @Time : 2021/5/10 10:18
# @File : RUN.PY
# @Author : 夜羽
# @Software: PyCharm
import time
from fastapi import FastAPI, Request, Request
from fastapi.middleware.cors import CORSMiddleware #跨域资源共享
from fastapi.templating import Jinja2Templates #模板渲染网页
import uvicorn #运行fastapi
from fastapi知识点教程 import app03
from fastapi知识点教程 import app04
from fastapi知识点教程 import app05
from fastapi知识点教程 import app06
from fastapi知识点教程 import app07
from fastapi知识点教程 import app08
#from coronavirus import application
from fastapi.staticfiles import StaticFiles #静态文件
#应用常见配置
app = FastAPI(
title='FastAPI 学习和 练习用的 API Docs', #标题
description='FastAPI教程 学习练习api,学习视频:https://www.bilibili.com/video/BV1iN411X72b 老师github库:https://github.com/liaogx/fastapi-tutorial', #描述
version='1.0.0', #版本号
docs_url='/docs', #路由地址
redoc_url='/redocs', #重置地址
)
app.mount(path="/static", app=StaticFiles(directory="./static"), name="static") #静态文件配置 # .mount()不要在分路由APIRouter().mount()调用,模板会报错
#拦截所有的请求 middleware中间键
@app.middleware('http')
async def add_process_time_header(request: Request, call_next): # call_next将接收request请求做为参数
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers['X-Process-Time'] = str(process_time) # 添加自定义的以“X-”开头的请求头
return response
# 跨域资源共享
app.add_middleware(
CORSMiddleware,
allow_origins=[
"http://127.0.0.1",
"http://127.0.0.1:8080"
],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
#prefix= 路径 tags=[] 名称
app.include_router(app03, prefix='/chapter03', tags=['第三章 请求参数和验证'])
app.include_router(app04, prefix='/chapter04', tags=['第四章 响应处理和fastapi设置'])
app.include_router(app05, prefix='/chapter05', tags=['第五章 fastapi的依赖注入系统'])
app.include_router(app06, prefix='/chapter06', tags=['第六章 fastapi的安全、认证和授权'])
app.include_router(app07, prefix='/chapter07', tags=['第七章 fastapi的数据库操作和多应用的目录结构设计'])
app.include_router(app08, prefix='/chapter08', tags=['第八章 中间键\跨域资源共享\后台任务\测试用例'])
#app.include_router(application, prefix='/chapter07', tags=['新冠病毒疫情跟踪器'])
if __name__ == '__main__':
uvicorn.run('RUN:app', host="127.0.0.1", port=8000, reload=True, debug=True, workers=1)
#woker=1进程数量
在一个文件中实现
@app.get("/11", tags=["渲染界面"],
responses={
403: {
"description": "Operation forbidden"}},)
async def root():
return {
"message": "Hello World"}
@app.get("/12", tags=["渲染界面1"],
responses={
403: {
"description": "Operation forbidden"}},)
async def root():
return {
"message": "Hello World"}
@app.get("/13", tags=["渲染界面2"],
responses={
403: {
"description": "Operation forbidden"}},)
async def root():
return {
"message": "Hello World"}
api备注
Path(None) 可为空 ,title=“这是一个标题”, description=“描述”, ge=1,le=10 大于1小于10, alias=‘别名’ #convert_underscores=True 转换为无下划线
default=[“默认值”],
值类型列子
def cookie(user_agent: Optional[str] = Header(None, convert_underscores=True, description="描述"),
x_token: List[str] = Header(None, description="描述")):
unm: int = Path(..., title="这是一个标题", description="描述", ge=1, le=10)
#查询:
values: list[str] = Query(default=["v1","v2"], alias='alias_name', title="这是一个标题", description="描述",)
@app03.get("/path_1/{unm}")
def path03(
values: list[str] = Query(default=["v1","v2"], alias='alias_name', title="这是一个标题", description="描述",),
unm: int = Path(..., title="这是一个标题", description="描述", ge=1, le=10)
#num: int =Path(None, title="这是一个标题", description="描述",ge=1,le=10)
api属性备注
“”"
备注内容
“”"
print("\033[31m5. --- cookkie 和 header ---\033[Om")#
@app03.get("/header") #不需要使用cookie
def cookie(user_agent: Optional[str] = Header(None, convert_underscores=True, description="XIANXI"), x_token: List[str] = Header(None, description="描述")): #convert_underscores=True 转换为无下划线
"""
有些http代理和服务器是不支持在请求中带有下划线的,convert_underscores=True转换为无下划线
:param user_agent: convert_underscores=True
:param x_token: 包含多个值得列表
:return: 返还定义的属性
"""
return {
"user_agent": user_agent, "x_token": x_token}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9wLZRynr-1631113988190)(C:\Users\gouguoxiong\Desktop\py后端\批注 2021-05-10.jpg)]
枚举(可选型)
from enum import Enum
class cityname(str,Enum): #枚举参数类型, 使用后可以选填下方参数
beijing = "beijing China"
shanghai = "shanghai China"
子应用
#应用常见配置
app = FastAPI(
title='FastAPI Tutorial and Coronavirus Tracker API Docs', #标题
description='FastAPI教程 新冠病毒疫情跟踪器API接口文档,项目代码:https://github.com/liaogx/fastapi-tutorial', #描述
version='1.0.0', #版本号
docs_url='/docs', #路由地址
redoc_url='/redocs', #重置地址
1.5api交互文档
可以写入内容
http://127.0.0.1:8000/docs
只显示不可更改
查询参数
1、查询参数概念(前端传递的数据给后端校验)
#多查询参数的列表,参数别名alias
Query
当你声明不属于路径参数
的其他函数参数时,它们将自动解释为“Query”参数,也就是查询参数。
查询参数就是一系列在URL?
之后的key-value键值对,每对键值对用 &
分割开来。例如
http://127.0.0.1:8000/items/?skip=0&limit=10
查询参数有两个,一个是skip
,一个是limit
,它们的值分别为0,10
由于它们都是URL的一部分,所以 “本质上” 它们都是字符串。
但是当你需要使用Python类型来声明query参数的时候(例如用int
),他们就会被转换为相应的类型并且依据这个类型来验证传入参数。
适用于Path参数的所有过程也适用于Query参数
- 编辑器支持
- 数据解析
- 数据验证
- 自动文档
from fastapi import APIRouter, Path, Query #APIRouter api路由器, Path 路径校验 Query 查询
from enum import Enum # 枚举
from typing import List, Optional #Optional 参数可以为空或已经声明的类型
print("\033[31m5. --- 查询参数, 和字符串验证 ---\033[Om")#
@app03.get("/quety")
def page_limit(page: int = 1 , limit: Optional[int] = None):
if limit:
return {
"page":page, "limit": limit}
return {
"page": page,}
@app03.get("/quety/bool/conversion")
def type_conversion(param: bool = False):
return param
@app03.post("/piery/validations")
def que(
value: str = Query(...,min_length=8, max_length=20, regex="^a"),
values: list[str] = Query(default=["v1","v2"], alias='alias_name')
): #多查询参数的列表,参数别名alias
return values, value
2.请求体和字段
当您需要将数据从客户端(例如浏览器)发送到API时,可以将其作为 “请求体
” 发送。
请求体是客户端发送到您的API的数据。 响应体是您的API发送给客户端的数据。
API几乎总是必须发送一个响应体,但是客户端并不需要一直发送请求体。
定义请求体,需要使用 Pydantic
模型。注意以下几点
-
不能通过GET请求发送请求体
-
发送请求体数据,必须使用以下几种方法之一:POST(最常见)、PUT、DELETE、PATCH如何实现请求体
-
当想实现全部接口的请求时:
@app.api_route("/api", methods=("GET", "POST", "PUT")) async def api(): return {"api": "GET, POST, PUT"}
实现请求体总共包含三个步骤。
第一步,从`pydantic`中导入`BaseModel`
```
from pydantic import BaseModel
```
第二步,创建请求体数据模型
声明请求体数据模型为一个类,且该类继承 BaseModel。所有的属性都用标准Python类。和查询参数一样:数据类型的属性如果不是必须的话,可以拥有一个默认值或者是可选None。否则,该属性就是必须的。
例如,声明了一个`JSON`对象
```python
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
```
所以访问链接的时候传入的请求体可以是下面两种,
```python
{
"name": "Foo",
"description": "An optional description",
"price": 45.2,
"tax": 3.5
}
```
另一种可以不传递默认值或者是可选值,(注意字典后面最后一个元素不需要逗号)
```python
{
"name": "Foo",
"price": 45.2
}
```
第三步、将模型定义为参数
将上面定义的模型添加到你的路径操作中,就和定义Path和Query参数一样的方式:
```python
from fastapi import FastAPI
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
app = FastAPI()
@app.post("/items/")
async def create_item(item: Item):
return item
```
声明参数的类型为你创建的模型 Item
这样当你使用postman选择post方法访问链接并传递一个值为
{
“name”: “Foo”,
“price”: 45.2
}
的请求体之后,会得到输出
{
“name”: “Foo”,
“price”: 45.2
}
3.cookie 和 header
安装postpai
使用:
cookie
print("\033[31m5. --- cookkie 和 header ---\033[Om")#
@app03.get("/cookie") #效果需要使用cookie
def cookie(cookie_id: Optional[str] = Cookie(None)): #使用cookie参数来定义cookie类
return {
"coookie_id": cookie_id}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OWgQIWJX-1631113988192)(C:\Users\gouguoxiong\Desktop\py后端\批注 2021-05-10 22222.jpg)]
header
print("\033[31m5. --- cookkie 和 header ---\033[Om")#
@app03.get("/header") #不需要使用cookie
def cookie(user_agent: Optional[str] = Header(None, convert_underscores=True, description="XIANXI"), x_token: List[str] = Header(None, description="描述")): #convert_underscores=True 转换为无下划线
"""
有些http代理和服务器是不支持在请求中带有下划线的,convert_underscores=True转换为无下划线
:param user_agent: convert_underscores=True
:param x_token: 包含多个值得列表
:return: 返还定义的属性
"""
return {
"user_agent": user_agent, "x_token": x_token}
响应数据进行规范和校验
1.响应模型类
#请求和响应的区别:返回响应不会返回密码
from pydantic import BaseModel, EmailStr #检验