我正在尝试使用 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"
}
]
}
"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
对字典进行编码。 - 调试 Litestar 模型查询参数作为字符串提供到 msgspec 转换中的实现。这显然不符合所需的类型。
预期行为:
我希望
input
查询参数能够正确解析并序列化到
Input
模型中,从而允许 GET 请求成功而不会出现验证错误。
问题: 如何在 Litestar GET 路由中正确传递 Pydantic 模型作为查询参数?我在序列化过程中缺少什么?有可能吗?
附加上下文:
- Litestar 版本:2.10.0
- Pydantic 版本:2.8.2
- httpx 版本:0.27.0
任何帮助或指导将不胜感激。
遇到的问题是 Litestar 预计查询参数将作为字符串传递。默认情况下,它不会自动将 JSON 字符串解析为 Pydantic 模型。
可以通过以下两种方式解决此问题:
1. 使用
Query
参数和
config=
可以使用
Query
参数明确地从查询字符串中提取数据,并使用
config=
来指定如何解析数据。在这种情况下,我们可以使用
Depends
来调用 Pydantic 模型的
.parse_obj
方法。
from pydantic import BaseModel
from litestar import Litestar, get, Controller
from litestar.params import Query
from typing import Depends
class Input(BaseModel):
foo: str
bar: str
class RootController(Controller):
path = "/"
@get()
def input(self, input: Input = Depends(Input.parse_obj, config=Query(alias="input"))) -> str:
return input.foo + input.bar
app = Litestar(route_handlers=[RootController])
在这个例子中,
Query(alias="input")
将告诉 Litestar 从名为 "input" 的查询参数中获取值。然后,
Depends(Input.parse_obj, ...)
将使用
Input.parse_obj
方法解析该值。
2. 将查询参数作为单独的参数传递
可以将
foo
和
bar
作为单独的查询参数传递,然后让 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
response = httpx.get("http://localhost:8000/", params={"foo": "test", "bar": "this"})
response.json()
这将使 Litestar 自动将
foo
和
bar
查询参数解析到
Input
模型中。
选择哪种方法?
-
如果的查询参数结构复杂且希望将 JSON 字符串直接传递给 API,则第一个方法(使用
Query
和Depends
)更适合。 - 如果的查询参数相对简单,则第二个方法(将查询参数作为单独的参数传递)更简洁易懂。
希望这些解决方案可以帮助解决问题!
标签:python,query-string,pydantic,litestar From: 78799973