如何在Litestar的GET路由中使用Pydantic模型作为查询参数
我尝试在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()
请求返回如下错误:
{ "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将字典编码后作为参数发送 - 调试Litestar模型实现,发现查询参数以字符串形式传入msgspec转换,不符合所需类型
预期行为:
期望input查询参数能被正确解析并序列化为Input模型,使GET请求成功且无验证错误。
问题:
如何在Litestar的GET路由中正确传递Pydantic模型作为查询参数?我在序列化过程中遗漏了什么?这是否可行?
额外环境信息:
- Litestar版本:2.10.0
- Pydantic版本:2.8.2
- httpx版本:0.27.0
在Litestar中处理GET请求的复杂查询参数(比如Pydantic模型),需要注意参数的传递格式和Litestar的解析配置,以下是具体解决方法:
方法一:使用扁平的查询参数(推荐)
GET请求的查询参数通常是键值对形式,Litestar默认会自动将同模型的扁平参数绑定到Pydantic模型,不需要嵌套传递,直接把模型字段作为顶级参数发送:
修改请求代码
import httpx params = { "foo": "test", "bar": "this" } response = httpx.get("http://localhost:8000/", params=params) print(response.text) # 输出 "testthis"
路由代码无需修改
原有的Input模型和路由处理函数保持不变,Litestar会自动将foo和bar参数映射到Input模型实例中。
方法二:启用嵌套查询参数解析
如果必须使用嵌套的input参数名传递,需要在Litestar中配置允许嵌套查询参数,并调整请求的传递方式:
1. 修改路由配置,启用嵌套解析
在@get装饰器中添加nested_query_parameters=True:
class RootController(Controller): path = "/" @get(nested_query_parameters=True) def input(self, input: Input) -> str: return input.foo + input.bar
2. 调整请求参数格式
不需要用json.dumps序列化,直接传递嵌套字典,httpx会自动将其转换为input[foo]和input[bar]形式的查询参数:
import httpx params = { "input": { "foo": "test", "bar": "this" } } response = httpx.get("http://localhost:8000/", params=params) print(response.text) # 输出 "testthis"
原代码失败原因
原代码用json.dumps把嵌套字典序列化为字符串传递,Litestar收到的是一个JSON格式的字符串,而不是它期望的字典结构。即使启用了嵌套解析,Litestar也不会自动将JSON字符串反序列化为字典,因此触发了验证错误。
内容的提问来源于stack exchange,提问作者casabre

