Fastapi教程003

 

Query参数

简单了解

当我们需要声明其他功能变量,但是不想将其设置为Path路径参数时,通常情况下我们会使用query参数去声明。

query参数通常情况下是在URL中用来表示的,以key-value的形式出现并且多个k-v之间是用&相连。

举个栗子:

  from fastapi import FastAPI

  app = FastAPI()

  fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"}]


  @app.get("/items/")
  async def read_item(skip: int = 0, limit: int = 10):
    return fake_items_db[skip : skip + limit]

当我们运行上面的Demo后,可通过下面的URL代码进行访问:

http://127.0.0.1:8000/items/?skip=0&limit=10

从上面的url中我们可以看到有两个查询参数分别是:

  • skip : 它的值是 0
  • limit: 它的值是 10

这两个参数被解释为URL的一部分,整个URL默认为string类型的。

当我们想要声明参数是python的基本数据类型的时候(例如上面的两个变量他们的值都是int类型),Fastapi可以自动为我们进行数据格式转换和验证。

基于以上的简单示范,相信大家对于Query参数有一个大概的了解,其实简单来说Query参数和Path参数的使用方法基本上是类似的:

  • 编辑器支持
  • 数据解析
  • 数据验证
  • 自动在文档中显示

默认值

通过上面的简单例子我们可以了解到Query参数并不与Path参数完全相同,因为它们是可有可无的,并不像Path参数必须存在,并且它们是可以有默认值的例如skip=0limit=10

最初的URL是:

http://127.0.0.1:8000/items/

加了默认查询参数Query以后可能是:

http://127.0.0.1:8000/items/?skip=0&limit=10

但是当你只添加一个skip参数也是没问题的,例如下面的例子:

http://127.0.0.1:8000/items/?skip=20

简单解释一下:

  • skip=20 在我们的函数内 skip的值是 20,这是我们自己在url中设置的

  • limit=10 由于我们并未在url中声明,所以 limit的值还是最初的默认值10

可选参数

当我们在Query参数的基础上,将参数的默认值设置为 None的时候,这个参数我们称为可选参数。

 from fastapi import FastAPI

  app = FastAPI()


  @app.get("/items/{item_id}")
  async def read_item(item_id: str, q: str = None):
      if q:
          return {"item_id": item_id, "q": q}
      return {"item_id": item_id}

在这个例子里我们可以看到q是一个Query参数,但是由于默认值是None所以又叫可选参数。 同时,Fastapi还可以明确的判断出 item_id是一个Path参数,但是q是一个可选参数。

Query参数的类型转换

还是从代码上解释吧,我们可以声明一个bool类型的参数,这些参数会被Fastapi自动解析成对应的值:

  from fastapi import FastAPI

  app = FastAPI()


  @app.get("/items/{item_id}")
  async def read_item(item_id: str, q: str = None, short: bool = False):
      item = {"item_id": item_id}
      if q:
          item.update({"q": q})
      if not short:
          item.update(
              {"description": "This is an amazing item that has a long description"}
          )
      return item

将上面的代码跑起来以后,你可以使用不同的URL去测试:

http://127.0.0.1:8000/items/foo?short=1

或者

http://127.0.0.1:8000/items/foo?short=True

或者

http://127.0.0.1:8000/items/foo?short=true

或者

http://127.0.0.1:8000/items/foo?short=on

或者

http://127.0.0.1:8000/items/foo?short=on

通过上面的URL测试,我们可以看到short参数的值都是True,当我们给short赋予其他值的时候都是False.

### Path参数和Query参数组合

当我们同时使用path参数和query参数时,Fastapi将会自动为我们判断出参数的类型。    

并且参数的定义是跟它们的定义顺序无关的,我们不需要特别去注意它们的顺序,同时Fastapi会自动根据定义的参数名去获取它们的值。

```
from fastapi import FastAPI

app = FastAPI()


@app.get("/users/{user_id}/items/{item_id}")
async def read_user_item(
    user_id: int, item_id: str, q: str = None, short: bool = False
):
    item = {"item_id": item_id, "owner_id": user_id}
    if q:
        item.update({"q": q})
    if not short:
        item.update(
            {"description": "This is an amazing item that has a long description"}
        )
    return item
```

代码解释: 在上面的代码里 `user_id` 和 `item_id `都是path参数本节不做说明,`read_user_item`中定义的`q`和`short`参数为query参数,并且`q`参数也叫可选参数,`short`参数有一个默认值为`False`.

必填的query参数

结合上面的例子来说,shortq参数都不是必须要填写的,因为我们在设置的时候给了默认值或者None,因此它们并不是必须要填写的。当我们给参数设置默认值并且默认值为None,那么这个参数叫做可选参数。

但是当我们想要声明一个必须参数的时候,我们只能通过不给参数添加默认值:

  from fastapi import FastAPI

  app = FastAPI()


  @app.get("/items/{item_id}")
  async def read_user_item(item_id: str, needy: str):
      item = {"item_id": item_id, "needy": needy}
      return item

在上面的例子里,我们设置了两个必填参数,其中参数item_idpath参数,needy参数是query参数并且值类型为str
在浏览器中我们可以输入:

http://127.0.0.1:8000/items/foo-item

当我们没添加needy参数的时候,我们的程序将会报错:

  {
    "detail": [
        {
            "loc": [
                "query",
                "needy"
            ],
            "msg": "field required",
            "type": "value_error.missing"
        }
    ]
  }

其中loc部分是错误字段,msg是错误信息上面的例子中由于我们没用填写必填字段needy所以报错,错误信息为field required

由于needy参数是必填的,因此我们需要在URL中进行填写如下:

http://127.0.0.1:8000/items/foo-item?needy=sooooneedy

当我们设置了needy参数后,再通过浏览器访问,我们将收到以下响应信息:

  {
    "item_id": "foo-item",
    "needy": "sooooneedy"
  }

在我们实际开发过程中,我们很有可能需求是有些参数是必填的,有些参数是可选的,所以我们在设置参数的时候可以将参数设置一个默认值(None也可以)那么这个参数就变成了可选参数,必填参数不设置默认值即可。 例如我们在注册一个网站,需要填写手机号、密码、生日,其中手机号、密码是必填的,生日是可选的,那么我们可以通过生日=None设置成可选参数,在注册账户的时候就可以不填写。


  代码实例:

  from fastapi import FastAPI

  app = FastAPI()


  @app.get("/items/{item_id}")
  async def read_user_item(item_id: str, needy: str, skip: int = 0, limit: int = None):
      item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit}
      return item

在这个例子中我们声明了三个query参数:

  • needy, 必填参数数据类型为 str
  • skip,一个int类型的数据,默认值为0
  • limit, 可选参数 int

这三个参数中skiplimit都可以不填,不过skip的值会是0,而limit的值为Null

可选参数声明类型

如果你正在使用mypy,当我们用以下方式声明时:

limit: int = None

我们会收到一个错误信息:

Incompatible types in assignment (expression has type "None", variable has type "int")

我们可以通过使用Optional来声明一个int类型值为None的变量:

  from typing import Optional

  limit: Optional[int] = None

在路径操作中书写方法与下面的代码类似:

  from typing import Optional

  from fastapi import FastAPI

  app = FastAPI()


  @app.get("/items/{item_id}")
  async def read_user_item(item_id: str, limit: Optional[int] = None):
      item = {"item_id": item_id, "limit": limit}
      return item

上面代码中的mypy是支持静态类型变成的python的变种所以参数定义与python有所区别,但是当我们使用python的时候可以直接将 limit: Optional[int] = None写成 limit: int = None,即按照正常编程习惯写即可。

总结

  • Query参数可声明为可选、必填、可设置默认值
  • 用法与Path参数基本一致
  • Query参数在有文档支持,可在交互式文档中看到

ps: 个人根据对文档的理解进行的翻译如有错误请指出,非机翻!