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

1、概述

通常對於Request Body不會經過get提交,對於get提交的參數通常稱爲是查詢參數。因此,若是是經過POTS,PUT等方式提交的參數信息,咱們通常是放到Request Body來提交到咱們的後端。html

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

示例以下:json

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。後端

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

嘗試提交參數什麼都不寫的狀況下:架構

 

http://127.0.0.1:8000/items/

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

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

 

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

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

 

Request Body 和 Query 和 Path的混合

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

那麼咱們一般接收此次參數的話通常怎麼接收吶?學習

示例代碼如:

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

相關文章
相關標籤/搜索