FastAPI--參數提交Request Body(3)


一、概述

一般對於Request Body不會通過get提交,對於get提交的參數一般稱為是查詢參數。所以,如果是通過POTS,PUT等方式提交的參數信息,我們一般是放到Request Body來提交到我們的后端。

對於如何接收和校驗請求體,FastApi提供的形式是使用:from pydantic import BaseModel

示例如下:

import uvicorn
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

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

在上面的模型中,如果提交的Item它必須是怎么樣的一個格式,比如name是必選字段,description是可選且默認為None, price是必選,且需要是float類型的,tax是可須且默認為None。

那客戶端如何提交上面那些參數吶?

嘗試提交參數什么都不寫的情況下:

 

http://127.0.0.1:8000/items/

使用JSON格式提交參數的情況下:

{
    "name":"Foo",
    "description":"An openfdsf",
    "price":45.4,
    "tax":3.5
}

 

故意提交錯誤參數格式請求:

{
    "name":"Foo",
    "description":"An openfdsf",
    "price":"45abc",
    "tax":3.5
}

 

Request Body 和 Query 和 Path的混合

在設計一些API過程中難免的可能也會需要綜合遇到上述的一些混搭的組合,需要同時多個參數的提交和獲取

那么我們通常接收這次參數的話一般怎么接收吶?

示例代碼如:

import uvicorn
from fastapi import FastAPI, Path
from pydantic import BaseModel

app = FastAPI()

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

@app.put("/items/{item_id}")
async def update_item(
        *,
        item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000),
        q: str = None,
        item: Item = None,
):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    if item:
        results.update({"item": item})
    return results

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

通過之前的學習,其實也很簡單道理也還是一樣,如上的示例請求的話:

 

url:

http://127.0.0.1:8000/items/1000?q=xiao

參數:

{
    "name":"Foo",
    "description":"An openfdsf",
    "price": 45.4,
    "tax":3.5
}

效果如下:

多個Request Body的提交

更復雜的業務其實會存在多體的Boay的提交,之前做的商城下單里面,客戶端有可能就會同時提交多個實體的對象信息到后端,如訂單實體,地址實體,商品信息實體等。

那么在Fastapi如何接受多個Body實體吶?通常以前的話,在bottle,通常直接的request.body 或 request.json就可以獲取客戶端部提交的信息了。

在Fastapi假設客戶端提交的參數是這樣的形式:

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

 

那如何的接收處理吶?

import uvicorn
from fastapi import FastAPI, Path
from pydantic import BaseModel

app = FastAPI()

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

class User(BaseModel):
    username: str
    full_name: 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

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

這種情況,其實就是客戶端提交多個實體對象。那可以定義多個模型對象即可。fastapi它會自動幫你處理提取信息。

 

http://127.0.0.1:8000/items/1000

 

 

如果另外再假設:

在Fastapi假設客戶端提交的參數是這樣的形式:

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

其實這種可能也不是不存在滴,那如何的讀取解析importance參數吶?既然參數有Query 和 Path,當然也會有 Body 。

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

app = FastAPI()

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

class User(BaseModel):
    username: str
    full_name: str = None

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

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

上面的代碼中我們引入了Body 並且在importance: int = Body(...)進行處理和提取:

 

如果另外再假設,客戶端提交的是一個單體對象內嵌的話,我們需要怎么處理?:

{
    "item": {
        "name": "Foo",
        "description": "The pretender",
        "price": 42.0,
        "tax": 3.2
    }
}

FastAPI提供了一個:

item: Item = Body(..., embed=True) 具體如下:

 

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

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str = None
    price: float
    tax: 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

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

 

請求示例如:

 

 

如果另外再假設,客戶端提交一個更復雜的嵌套模型的話,怎么辦?麻蛋的 肯定也是會有這樣的情況滴! 嵌套里面有列表有實體。比如:

{
    "name": "Foo",
    "description": "The pretender",
    "price": 42.0,
    "tax": 3.2,
    "tags": ["rock", "metal", "bar"],
    "image": {
        "url": "http://example.com/baz.jpg",
        "name": "The Foo live"
    }
}

這時候,我們就需要所謂的子內嵌啦:

import uvicorn
from typing import Set

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Image(BaseModel):
    url: str
    name: str

class Item(BaseModel):
    name: str
    description: str = None
    price: float
    tax: float = None
    tags: Set[str] = []
    image: Image = None

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

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

如上代碼,Item里面包含了Image,也包含了,tags類型的列表定義。

 

 

MMP更深層的嵌套也是可以定義的如:

{
    "name":"Foo",
    "description":"The pretender",
    "price":42,
    "items":[
        {
            "name":"Foo",
            "description":"The pretender",
            "price":42,
            "tax":3.2,
            "tags":[
                "rock",
                "metal",
                "bar"
            ],
            "image":{
                "url":"http://example.com/baz.jpg",
                "name":"The Foo live"
            }
        },
        {
            "name":"Foo2",
            "description":"The 2",
            "price":422,
            "tax":3.2,
            "tags":[
                "rock",
                "metal",
                "bar"
            ],
            "image":{
                "url":"http://example.com/baz.jpg",
                "name":"The Foo live"
            }
        }
    ]
}

對應的解析為:

import uvicorn

from fastapi import FastAPI
from pydantic import BaseModel
from typing import List, Set

app = FastAPI()

class Image(BaseModel):
    url: str
    name: str

class Item(BaseModel):
    name: str
    description: str = None
    price: float
    tax: float = None
    tags: Set[str] = []
    # images: List[Image] = None
    image: Image = None

class Offer(BaseModel):
    name: str
    description: str = None
    price: float
    items: List[Item]

@app.post("/offers/")
async def create_offer(*, offer: Offer):
    return offer

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

 

請求url

http://127.0.0.1:8000/offers

 

Request Body的Field

Field字段的意思其實就是類似上面Query, Path,也同樣給Body內的字段的信息添加相關的校驗。

也就是說。通過Field來規范提交的Body參數信息。比如:

import uvicorn

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

app = FastAPI()

class Item(BaseModel):
    name: str
    description: str = Field(None, title="標題啊", description="錯誤提示文字啊", max_length=30)
    price: float = Field(..., gt=0, description="錯誤提示文字啊")
    tax: 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

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

 

上面的意思就是和之前定義參數校驗其實一樣

正常情況:

{
    "item":{
        "name": "Foo",
        "description": "The pretender",
        "price": 42.0,
        "tax": 3.2

    }
}

 

 

 

 

異常情況:

{
    "item":{
        "name": "Foo",
        "description": "The pretender sssssssssssssssss",
        "price": 42.0,
        "tax": 3.2

    }
}

 

 

其他數據類型的校驗

對於數據格式的校驗,通常,我們不止於

  • int

  • float

  • str

  • bool

但是提交參數不止於上述的幾種格式,有時候比如是對手機號碼的校驗,有些時候是時間類型的校驗等

其他類型:

其他數據類型¶ 以下是您可以使用的一些其他數據類型(來自官方文檔):

  • UUID:

    • 一個標准的“通用唯一標識符”,在許多數據庫和系統中常見於ID。

    • 在請求和答復中,將表示為str.

  • datetime.datetime:

    • 一只Pythondatetime.datetime.

    • 在請求和答復中,將表示為str采用ISO 8601格式,如:2008-09-15T15:53:00+05:00.

  • datetime.date:

    • Pythondatetime.date.

    • 在請求和答復中,將表示為str采用ISO 8601格式,如:2008-09-15.

  • datetime.time:

    • 一只Pythondatetime.time.

    • 在請求和答復中,將表示為str采用ISO 8601格式,如:14:23:55.003.

  • datetime.timedelta:

    • 一只Pythondatetime.timedelta.

    • 在請求和答復中,將表示為float總秒數。

    • Pydantic還允許將其表示為“ISO 8601時間差異編碼”,有關更多信息,請參閱文檔。.

  • frozenset:

    • 在請求和答復中,將其視為set:

    • 在請求中,將讀取列表,消除重復,並將其轉換為set.

    • 在答復中,set將轉換為list.

    • 生成的架構將指定set值是唯一的(使用JSONSchema的uniqueItems).

  • bytes:

    • 標准Pythonbytes.

    • 在請求和答復中將被視為str.

    • 生成的架構將指定它是str帶着binary“格式”。

  • Decimal:

    • 標准PythonDecimal.

    • 在請求和響應中,處理方式與float.

所以我還可以使用其他類型來校驗:

 

import uvicorn

from datetime import datetime, time, timedelta
from uuid import UUID

from fastapi import Body, FastAPI

app = FastAPI()


@app.put("/items/{item_id}")
async def read_items(
        item_id: UUID,
        start_datetime: datetime = Body(None),
        end_datetime: datetime = Body(None),
        repeat_at: time = Body(None),
        process_after: timedelta = Body(None),
):
    start_process = start_datetime + process_after
    duration = end_datetime - start_process
    return {
        "item_id": item_id,
        "start_datetime": start_datetime,
        "end_datetime": end_datetime,
        "repeat_at": repeat_at,
        "process_after": process_after,
        "start_process": start_process,
        "duration": duration,
    }

if __name__ == '__main__':
    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)

 

 

本文參考鏈接:

http://www.zyiz.net/tech/detail-119883.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM