我正在尝试使用 Litestar 创建一条 GET 路由,该路由利用 Pydantic 模型作为查询参数。但是,序列化并没有按预期工作。
这是重现我的问题的最小示例:
from pydantic import BaseModel
from litestar import Litestar, get, Controller
class Input(BaseModel):
foo: str
bar: str
class RootController(Controller):
path = "/"
@get()
def input(self, input: Input) -> str:
return input.foo + input.bar
app = Litestar(route_handlers=[RootController])
以及以下 GET 请求:
import httpx
import json
params = {
"input": {
"foo": "test",
"bar": "this"
}
}
def prepare_encode(params: dict) -> dict:
for key, value in params.items():
if isinstance(value, dict):
params[key] = json.dumps(value, indent=None)
return params
params = prepare_encode(params)
response = httpx.get("http://localhost:8000/", params=params)
response.json()
GET 请求导致以下错误:
{
"status_code": 400,
"detail": "Validation failed for GET /?input=%7B%22foo%22%3A%20%22test%22%2C%20%22bar%22%3A%20%22this%22%7D",
"extra": [
{
"message": "Input should be a valid dictionary or instance of Input"
}
]
}
查询参数似乎没有正确序列化到
Input
Pydantic 模型中。
我尝试过的:
json.dumps
对字典进行编码,然后将其作为参数发送。预期行为: 我希望
input
查询参数能够正确解析并序列化到 Input
模型中,从而允许 GET 请求成功而不会出现验证错误。
问题: 如何在 Litestar GET 路由中正确传递 Pydantic 模型作为查询参数?我在序列化过程中缺少什么?有可能吗?
其他背景:
任何帮助或指导将不胜感激。
实际上,你的请求方式和处理方式都存在问题。首先,我无法在 docs 中找到使用
Pydantic
模型作为查询参数的可能性 FastAPI 。不过你可以通过 DI 机制自己实现类似的逻辑:
def build_input(foo: str, bar: str) -> Input:
"""Prepare input model from query params."""""
return Input(foo=foo, bar=bar)
class RootController(Controller):
path = "/"
@get(dependencies={"input": Provide(build_input)})
def input(self, input: Input) -> str:
return input.foo + input.bar
其次,如果您想使用嵌套结构作为输入,您最好使用
POST
方法。
{
"input": {
"foo": "test",
"bar": "this"
}
}
否则,上面的字典在用作查询时将被转换为以下字符串:
%7B%22foo%22%3A%20%22test%22%2C%20%22bar%22%3A%20%22this%22%7D
我假设您想做的是以下事情:
response = httpx.get(
"http://localhost:8000/",
params={
"foo": "test",
"bar": "this"
}
)
有了这些改变,一切似乎都正常了!