fastapi教程-进阶(三)

参考内容

在fastapi教程的前几篇教程里,我们学习了如何声明路径参数、查询参数和请求体,这篇我们会对这些参数进行扩展学习,学习更多的用法

Query Parameters

我们先看一个例子:

from typing import Optional

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(q: Optional[str] = Query(None, min_length=3, max_length=50, regex="^fixedquery$")):
    results = {
    
    "items": [{
    
    "item_id": "Foo"}, {
    
    "item_id": "Bar"}]}
    if q:
        results.update({
    
    "q": q})
    return results

与之前的例子相比,发生了一些改变:

from fastapi import FastAPI, Query
async def read_items(q: Optional[str] = Query(None, min_length=3, max_length=50, regex="^fixedquery$")):

声明参数的时候,不再是单纯的指定None,而是调用了Query
通过这种方式,对q做了验证限制:

  1. 非必填
  2. 最大长度为50
  3. 最小长度为3
  4. 可以匹配正则表达式

尝试请求http://127.0.0.1:8000/items/?q=a,会发现返回了错误提示:

{
    
    
  "detail": [
    {
    
    
      "loc": [
        "query",
        "q"
      ],
      "msg": "ensure this value has at least 3 characters",
      "type": "value_error.any_str.min_length",
      "ctx": {
    
    
        "limit_value": 3
      }
    }
  ]
}

再次尝试http://127.0.0.1:8000/items/?q=test:

{
    
    
  "detail": [
    {
    
    
      "loc": [
        "query",
        "q"
      ],
      "msg": "string does not match regex \"^fixedquery$\"",
      "type": "value_error.str.regex",
      "ctx": {
    
    
        "pattern": "^fixedquery$"
      }
    }
  ]
}

除此之外,Query还支持其他的属性:

  1. alias: 参数别名
  2. description: 参数描述
  3. title:参数标题
  4. deprecated:表示该接口已被移除
from typing import Optional

from fastapi import FastAPI, Query

app = FastAPI()


@app.get("/items/")
async def read_items(
        q: Optional[str] = Query(..., title="Query string",
                                 description="Query string for the items to search in the database that have a good match",
                                 alias="item-query")):
    results = {
    
    "items": [{
    
    "item_id": "Foo"}, {
    
    "item_id": "Bar"}]}
    if q:
        results.update({
    
    "q": q})
    return results

打开http://127.0.0.1:8000/docs, 我们会发现页面发生了变化,并且请求的参数名也变成了别名:
在这里插入图片描述
这里我们会发现item-query变成了必填,这是因为,我们将Query(None)替换成了Query(...)

Path Parameters

依旧是一个例子:

from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.get("/items/{item_id}")
async def read_items(
        *,
        item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000),
        q: str,
        size: float = Query(..., gt=0, lt=10.5)
):
    results = {
    
    "item_id": item_id}
    if q:
        results.update({
    
    "q": q})
    return results

在这里,用Path来声明路径参数,通过这种方式,对item_id做了验证限制:

扫描二维码关注公众号,回复: 15274892 查看本文章
  1. item_id是必填的
  2. item_id大于等于0
  3. item_id小于等于1000

除此之外,我们可以发现方法的第一个参数是*,它的作用什么呢?
如果我们想不用Query来声明q,并想将q设为必填的,并且想用Path来声明item_id,这时我们就要用到*。因为python并不会对*做任何操作,但是python会将*之后的参数作为关键字参数来看待,因此,即使没有用Query,python也会把它当作有Query(...)来待

在从fastapi导入PathQuery时,其实导入的是方法,当它们被调用的时候,会返回同名的类。这些同名的类都是Param的子类,因此在声明参数时,他们都是有相同的属性的。在这里插入图片描述

Body Parameters

多个body参数

还是以一个例子开始

from typing import Optional

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


class User(BaseModel):
    username: str
    full_name: Optional[str] = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, user: User):
    results = {
    
    "item_id": item_id, "item": item, "user": user}
    return results

在这个例子里,fastapi会注意到不止一个body参数,此时的请求体是这样的:

{
    
    
  "item": {
    
    
    "name": "string",
    "description": "string",
    "price": 0,
    "tax": 0
  },
  "user": {
    
    
    "username": "string",
    "full_name": "string"
  }
}

fastapi会根据请求自动处理参数,以便用item和user可以接收到其内容
假如此时我们想在请求体中增加一个参数,例如:

{
    
    
    "item": {
    
    
        "name": "Foo",
        "description": "The pretender",
        "price": 42.0,
        "tax": 3.2
    },
    "user": {
    
    
        "username": "dave",
        "full_name": "Dave Grohl"
    },
    "importance": 5
}

这时我们该如何写参数呢

from typing import Optional

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


class User(BaseModel):
    username: str
    full_name: Optional[str] = None


@app.put("/items/{item_id}")
async def update_item(
    item_id: int, item: Item, user: User, importance: int = Body(...)
):
    results = {
    
    "item_id": item_id, "item": item, "user": user, "importance": importance}
    return results

嵌入单一body参数

一般情况下,我们声明一个body参数时,fastapi会这样解析:

{
    
    
  "name": "string",
  "description": "string",
  "price": 0,
  "tax": 0
}

如果我们想要下面这样的结构呢

{
    
    
  "item": {
    
    
    "name": "string",
    "description": "string",
    "price": 0,
    "tax": 0
  }
}

可以这样写

from typing import Optional

from fastapi import Body, FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item = Body(..., embed=True)):
    results = {
    
    "item_id": item_id, "item": item}
    return results

Field

前面我们学习了如果给QueryPath增加验证限制,这里会介绍Body如何增加验证限制

from typing import Optional

from fastapi import Body, FastAPI
from pydantic import BaseModel, Field

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Optional[str] = Field(
        None, title="The description of the item", max_length=300
    )
    price: float = Field(..., gt=0, description="The price must be greater than zero")
    tax: Optional[float] = None


@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item = Body(..., embed=True)):
    results = {
    
    "item_id": item_id, "item": item}
    return results

通过上面的例子不难看出Field的属性和QueryPath是一样的。上面我们说过QueryPathParam的子类,这里的Field本身是方法,返回了FieldInfo类,而ParamFieldInfo的子类,因此他们的属性都是一样的在这里插入图片描述
Body也是一个方法,他返回了继承自FieldInfoBody在这里插入图片描述

上述栗子均放到git上啦,地址:戳这里

猜你喜欢

转载自blog.csdn.net/weixin_40156487/article/details/108281234