这次主要聊聊Fastapi 中,查询参数和路径参数的使用及校校验,Path 是为路径参数声明校验和元数据,而 Query 是 为查询参数声明校验和元数据。
两个的区别就是,路径参数是跟在路径后面的,例如:/path/1 ,1 即为路径参数;查询参数是键值对传值,例如:/path/q=1 ,q=1 即为查询参数
介绍完后,下面进入实例操作环节…
查询参数和字符串校验 ?
查询参数校验
FastAPI 允许参数声明额外的信息和校验,以下面的应用程序为例:
from?typing?import?Optional
from?fastapi?import?FastAPI
app?=?FastAPI()
@app.get("/items")
def?read_items(q:?Optional[str]?=?None):
????"""
????:param?q:
????:return:
????"""
????results?=?{"items":?[{"item_id":?"Foo"},?{"item_id":?"Bar"}]}
????if?q:
????????results.update({"q":?q})
????return?results
上述实例是设置了查询参数q ,设置的类型为str ,默认值为None 。Optional 是用于定义为可选参数,所以此时的q 为可选参数,请求时可传可不传。
根据上述实例继续增加额外的校验,也就是增加一个约束条件。增加后的应用程序为例如下:
from?typing?import?Optional
from?fastapi?import?FastAPI
from?fastapi?import?Query
app?=?FastAPI()
@app.get("/items_check")
def?read_items_check(q:?Optional[str]?=?Query(None,?min_length=3,?max_length=5)):
????"""
????约束条件,校验查询参数的长度
????:param?q:
????:return:
????"""
????results?=?{"items":?[{"item_id":?"Foo"},?{"item_id":?"Bar"}]}
????if?q:
????????results.update({"q":?q})
????return?results
上述实例中的使用Query(None) 替换默认值None ,Query 的第一个参数同样也是用于定义默认值。
所以:
q:?str?=?Query(None)
等同于:
q:?str?=?None
也等同于:
q:?Optional[str]?=?None
Query() 主要是将其参数声明为查询参数,可以将更多的参数传递给Query() 中:
q:?Optional[str]?=?Query(None,?min_length=3,?max_length=5)
注释信息:
max_length :设置q 参数的值,长度最大为10 min_length :设置q 参数的值,长度最小为3
请求接口:
http://127.0.0.1:8000/items_check?q=1
{
????"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_check?q=111111
{
????"detail":?[{
????????"loc":?["query",?"q"],
????????"msg":?"ensure?this?value?has?at?most?5?characters",
????????"type":?"value_error.any_str.max_length",
????????"ctx":?{
????????????"limit_value":?5
????????}
????}]
}
从上述返回数据可以看到,如果传参不满足参数需要的长度时,就会抛出异常信息。
添加正则表达式
定义一个参数值必须匹配的正则表达式:
from?typing?import?Optional
from?fastapi?import?FastAPI
from?fastapi?import?Query
app?=?FastAPI()
@app.get("/items_regular")
def?read_items_regular(q:?Optional[str]?=?Query(None,?min_length=3,?max_length=50,?regex="^fixedquery$")):
????"""
????添加正则表达式【定义一个参数值必须匹配的正则表达式】
????:param?q:
????:return:
????"""
????results?=?{"items":?[{"item":?"Foo"},?{"itme_id":?"Bar"}]}
????if?q:
????????results.update({"q":?q})
????return?results
这个指定的正则表达式通过以下规则检查接收到的参数值:
^ :以该符号之后的字符开头,符号之前没有字符。fixedquery : 值精确地等于 fixedquery 。$ : 到此结束,在 fixedquery 之后没有更多字符。
请求接口:
http://127.0.0.1:8000/items_regular?q=1
q 参数的值如果不是fixedquery ,因匹配失败,则会抛出异常信息:
{
????"detail":?[{
????????"loc":?["query",?"q"],
????????"msg":?"ensure?this?value?has?at?least?3?characters",
????????"type":?"value_error.any_str.min_length",
????????"ctx":?{
????????????"limit_value":?3
????????}
????}]
}
q 参数的值如果是fixedquery ,因匹配成功,返回正常信息:
{
????"items":?[{
????????"item":?"Foo"
????},?{
????????"itme_id":?"Bar"
????}],
????"q":?"fixedquery"
}
声明必须参数 / 默认值
默认值:
可以向 Query 的第一个参数传入 None 用作查询参数的默认值,以同样的方式也可以传递其他默认值。
假设想要声明查询参数 q ,使其min_length 为 3 ,并且默认值为 fixedquery :
from?typing?import?Optional
from?fastapi?import?FastAPI
from?fastapi?import?Query
app?=?FastAPI()
@app.get("/items_default")
def?read_item_default(q:?str?=?Query("fixedquery",?min_length=3)):
????"""
????设置默认值
????:param?q:
????:return:
????"""
????results?=?{"items":?[{"item":?"Foo"},?{"itme_id":?"Bar"}]}
????if?q:
????????results.update({"q":?q})
????return?results
请求接口:
http://127.0.0.1:8000/items_default
{
????"items":?[{
????????"item":?"Foo"
????},?{
????????"itme_id":?"Bar"
????}],
????"q":?"fixedquery"
}
声明必须参数:
如果不需要参数默认值时,只需要不声明默认值即可成为必须参数。例如:
q:?str
或者
q:?str?=?Query(...)
Query 中的三个点就是用作第一个参数值,这是Query 设置必须参数时必须要使用的。
注释信息:
- 它是一个特殊的单独值,和省略号字面意思
… 一样。用于用户定义容器数据类型的特殊值,通常与扩展切片语法一起使用。省略号是类型的唯一实例。EllipsisType 类型。
利用Query 声明必须参数,实例如下:
from?typing?import?Optional
from?fastapi?import?FastAPI
from?fastapi?import?Query
app?=?FastAPI()
@app.get("/items_must")
def?read_item_must(q:?str?=?Query(...,?min_length=3)):
????"""
????声明为必需参数
????:param?q:
????:return:
????"""
????results?=?{"items":?[{"item":?"Foo"},?{"itme_id":?"Bar"}]}
????if?q:
????????results.update({"q":?q})
????return?results
请求接口:
http://127.0.0.1:8000/items_must
{
????"detail":?[{
????????"loc":?["query",?"q"],
????????"msg":?"field?required",
????????"type":?"value_error.missing"
????}]
}
提示异常错误,因为没有传q 参数而抛出错误信息。
再次请求接口:
http://127.0.0.1:8000/items_must?q=hehe
{
????"items":?[{
????????"item":?"Foo"
????},?{
????????"itme_id":?"Bar"
????}],
????"q":?"hehe"
}
再次请求接口,并传q 参数后,返回正常数据。
查询参数列表 / 多个值
当使用 Query 地定义查询参数时,还可以声明它去接收一组值,或换句话来说,接收多个值。
例如,要声明一个可在 URL 中出现多次的查询参数 q ,可以这样写:
from?typing?import?Optional
from?fastapi?import?FastAPI
from?fastapi?import?Query
app?=?FastAPI()
@app.get("/items_list")
def?read_item_list(t:?List[str]?=?Query(["foo",?"bar"]),?q:?list[str]?=?Query(...)):
????"""
????查询参数列表?/?多个值;具有默认值的查询参数列表?/?多个值
????:param?t:
????:param?q:
????:return:
????"""
????results?=?{"t":?t}
????if?q:
????????results?|=?{"q":?q}
????return?results
@app.get("/items_list")
def?read_list(t:?list?=?Query(["foo",?"bar"]),?q:?Optional[list[str]]?=?Query(None)):
????"""
????查询参数列表?/?多个值;具有默认值的查询参数列表?/?多个值
????:param?t:
????:param?q:
????:return:
????"""
????results?=?{"t":?t}
????if?q:
????????results?|=?{"q":?q}
????return?results
上述两个实例,都是处理多值和多值默认值,区别的是第一个是q 是必须参数,而第二个的q 是非必须参数
参数注释:
输入如下网址:
http://127.0.0.1:8000/items_list?q=hah&q=lili
{
????"t":?["foo",?"bar"],
????"q":?["hah",?"lili"]
}
声明更多元数据
添加更多有关该参数的信息。
这些信息将包含在生成的 OpenAPI 模式中,并由文档用户界面和外部工具所使用。
添加 title 、description 和 alias ,实例代码如下:
from?typing?import?Optional
from?fastapi?import?FastAPI
from?fastapi?import?Query
app?=?FastAPI()
@app.get("/metadata")
def?read_metadata(q:?Optional[str]?=?Query(None,
???????????????????????????????????????????alias="item",
???????????????????????????????????????????title="查询参数",
???????????????????????????????????????????description="描述信息...",
???????????????????????????????????????????min_length=3,?deprecated=True)):
????"""
????声明更多元数据(添加更多有关该参数的信息)
????:param?q:
????:return:
????"""
????results?=?{"items":?[{"item":?"Foo"},?{"itme_id":?"Bar"}]}
????if?q:
????????results.update({"q":?q})
????return?results
参数注释:
title 和 description 主要是显示在文档(可能有些浏览器不显示title )alias 是为q 取的别名,此时有了别名后,使用q 不再生效deprecated=True 是弃用q 参数,主要显示在文档上
输入如下网址:
http://127.0.0.1:8000/metadata?item=haha
{
????"items":?[{
????????"item":?"Foo"
????},?{
????????"itme_id":?"Bar"
????}],
????"q":?"haha"
}
路径参数和数值校验 ?
路径参数数值校验
from?fastapi?import?FastAPI
from?fastapi?import?Path
app?=?FastAPI()
@app.get("/item/{item_id}")
def?read_item(item_id:?int?=?Path(...,?title="路径参数",?ge=1)):
????"""
????数值校验:大于等于
????:param?item_id:
????:return:
????"""
????results?=?{"item_id":?item_id}
????return?results
@app.get("/items/{item_id}")
def?read_items(item_id:?int?=?Path(...,?title="路径参数",?gt=0,?le=1000)):
????"""
????数值校验:大于和小于等于
????:param?item_id:?
????:return:
????"""
????results?=?{"item_id":?item_id}
????return?results
参数注释:
ge=1 :大于等于 1 gt=0 :大于 0 le=1000 :小于等于 1000 lt :小于
输入如下网址:
http://127.0.0.1:8000/item/1
{
????"item_id":?1
}
输入如下网址:
http://127.0.0.1:8000/items/0
{
????"detail":?[
????????{
????????????"loc":?[
????????????????"path",
????????????????"item_id"
????????????],
????????????"msg":?"ensure?this?value?is?greater?than?0",
????????????"type":?"value_error.number.not_gt",
????????????"ctx":?{
????????????????"limit_value":?0
????????????}
????????}
????]
}
注意事项:
- 数值校验只针对数值类型,也就是[ int 和 float ]。
- 如果你设置str类型去进行数值校验,会抛出异常。
声明元数据
声明路径参数的元数据和查询路径元数据类似,区别就是路径参数使用的是Path 、查询参数使用的Query
例如,要声明路径参数 item_id 的 title 、alias 、description 、gt 、le 元数据值,可以输入:
from?fastapi?import?FastAPI
from?fastapi?import?Path
app?=?FastAPI()
@app.get("/metadata/{item}")
def?read_metadata(item_id:?int?=?Path(...,?title="路径参数",
??????????????????????????????????????alias="item",?description="描述信息...",?gt=0,?le=1000)):
????"""
????声明元数据
????:param?item_id:
????:return:
????"""
????results?=?{"item_id":?item_id}
????return?results
参数注释:
title 和 description 主要是显示在文档(可能有些浏览器不显示title )alias 是为item_id 取的别名,此时有了别名后,记得把@app.get("/metadata/{item_id}") 替换成@app.get("/metadata/{item}")
输入如下网址:
http://127.0.0.1:8000/metadata/1
{
????"item_id":?1
}
注意事项:
- 路径参数总是必需的,因为它必须是路径的一部分。
- 所以,你应该在声明时使用 … 将其标记为必需参数。
- 然而,即使你使用 None 声明路径参数或设置一个其他默认值也不会有任何影响,它依然会是必需参数。
查询参数和路径参数结合
例如,同时使用Path 和Query ,可以输入:
from?fastapi?import?FastAPI
from?fastapi?import?Path
app?=?FastAPI()
@app.get("/combine/{item_id}")
def?read_combine(item_id:?int?=?Path(...,?gt=0,?le=1000),?q:?int?=?Query(...,?ge=1)):
????"""
????参数结合
????:param?item_id:
????:param?q:
????:return:
????"""
????results?=?{"item_id":?item_id}
????if?q:
????????results?|=?{"q":?q}
????return?results
@app.get("/combines/{item_id}")
def?read_combines(*,?item_id:?int?=?Path(...,?gt=0,?le=1000),?q:?int):
????"""
????参数结合
????:param?item_id:
????:param?q:
????:return:
????"""
????results?=?{"item_id":?item_id}
????if?q:
????????results?|=?{"q":?q}
????return?results
如果查询参数需要声明元数据,则使用Query 来定义,如果不需要则可使用q: int ,但是前提要在函数的第一个参数位置放置一个* 号。
Python 不会对该 * 做任何事情,但是它将知道之后的所有参数都应作为关键字参数(键值对),也被称为 kwargs ,来调用。
今天先聊到这里吧,以上总结或许能帮助到你,或许帮助不到你,但还是希望能帮助到你,如有疑问、歧义,直接私信留言会及时修正发布;非常期待你的一键 3 连【 点赞、收藏、分享 】 哟,谢谢!
未完成,待续……
一直在努力,希望你也是!
?
|