Not rendering multi-select in API doc while using Pydantic model #8522
-
First Check
Commit to Help
Example Codeimport typing
from fastapi import FastAPI, Query, Depends
from pydantic import BaseModel
from enum import Enum
app = FastAPI()
class Status(str, Enum):
SUCCESS = "SUCCESS"
REFUND = "REFUND"
FAIL = "FAIL"
CANCEL = "CANCEL"
@app.get("/working-example/")
async def root_with_normal_query_params(status_in: typing.List[Status] = Query(...)):
return {"status_inputs": status_in}
class StatusModel(BaseModel):
status_in: typing.List[Status]
@app.get("/not-working-example/")
async def root_with_pydantic(status_inputs: StatusModel = Depends()):
return {"status_inputs": status_inputs}DescriptionThe API docs are not generating the multi-select option while using the Pydantic model for the query/request parser. without using Pydantic modelwith using Pydantic modelOperating SystemLinux Operating System DetailsNo response FastAPI Version0.70.1 Python VersionPython 3.9.11 Additional ContextNo response |
Beta Was this translation helpful? Give feedback.
Replies: 17 comments
-
|
Hmm that is interesting. I reproduced it but I didn't had the time to follow the logic of FastAPI when it resolves the dependencies and the connection of that logic to the buildup of the |
Beta Was this translation helpful? Give feedback.
-
|
Any thoughts @JarroVGIT :) |
Beta Was this translation helpful? Give feedback.
-
|
@JarroVGIT @jerinpetergeorge Working example you provided is QUERY parameters And non working example you provided is REQUEST BODY (not QUERY) and in docs it provides Additional note: HTTP GET can not go with request body |
Beta Was this translation helpful? Give feedback.
-
|
I figured that as well, but unfortunately that does not seem to be the case. The docs are saying us that when defining a param with a default value of from re import S
import typing
from fastapi import FastAPI, Query, Depends, File
from pydantic import BaseModel, Field
from enum import Enum
app = FastAPI()
#----------------------------------------------
class Status(Enum):
SUCCESS = "SUCCESS"
REFUND = "REFUND"
FAIL = "FAIL"
CANCEL = "CANCEL"
#class with list of Enum:
class StatusModelWithListEnum(BaseModel):
status_in: list[Status] = Query()
#class with Enum:
class StatusModelNoList(BaseModel):
status_in: Status = Query(...)
#class with list of str:
class OtherModelWithListStr(BaseModel):
some_param: list[str] = Query(...)
#class with str:
class OtherModelNoList(BaseModel):
some_param: list[str] = Query(...)
#----------------------------------------------
#The following 4 endpoints do not show correctly in the docs,
#as they are referencing pydantic models.
@app.get("/statusmodel-list")
async def statusmodel_list(par: StatusModelWithListEnum = Depends()):
return {"status_inputs": par}
#shows as request body.
@app.get("/statusmodel-nolist")
async def statusmodel_nolist(par: StatusModelNoList = Depends()):
return {"status_inputs": par}
#shows as query
@app.get("/stringmodel-list")
async def stringmodel_list(par: OtherModelWithListStr = Depends()):
return {"status_inputs": par}
#shows as request body
@app.get("/stringmodel-nolist")
async def stringmodel_nolist(par: StatusModelNoList = Depends()):
return {"status_inputs": par}
#shows as query
@app.get("/no-model-string-list")
async def no_model_string_list(par: list[str] = Query()):
return {"status_inputs": par}
#as per docs, shows as query!
#----------------------------------------------
#The following two endpoint will show correctly.
@app.get("/status-list-direct-in-param")
async def status_list_in_param(par: list[Status] = Query()):
return {"status_inputs": par}
@app.get("/status-nolist")
async def stringmodel_nolist(par: Status = Query()):
return {"status_inputs": par}
#----------------------------------------------
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000, ) The issue is real, it shouldn't behave this way. |
Beta Was this translation helpful? Give feedback.
-
|
@JarroVGIT yeah, I get it now! |
Beta Was this translation helpful? Give feedback.
-
|
I think using Pydantic shows everything in body. I may be wrong. |
Beta Was this translation helpful? Give feedback.
-
|
Is there a fix in the works for this issue? |
Beta Was this translation helpful? Give feedback.
-
|
Not AFAIK |
Beta Was this translation helpful? Give feedback.
-
|
@jerinpetergeorge Seems like using a Dataclass instead can get around this issue if you're able to make the swap. |
Beta Was this translation helpful? Give feedback.
-
How? Can you give an example? I tried these - it didn't seem to work
Moreover, the reason why I choose the Pydantic is that the superpower to parse the inputs - without the Pydantic model/feature I would be much disappointed 😞 @bshea5 |
Beta Was this translation helpful? Give feedback.
-
|
You can use import typing
from enum import Enum
from fastapi import FastAPI, Query, Depends
from pydantic.dataclasses import dataclass
app = FastAPI()
class Status(str, Enum):
SUCCESS = "SUCCESS"
REFUND = "REFUND"
FAIL = "FAIL"
CANCEL = "CANCEL"
@app.get("/working-example/")
async def root_with_normal_query_params(status_in: typing.List[Status] = Query(...)):
return {"status_inputs": status_in}
@dataclass
class StatusModel:
status_in: list[Status] = Query(...)
@app.get("/not-working-example/") # it now works
async def root_with_pydantic(status_inputs: StatusModel = Depends()):
return {"status_inputs": status_inputs} |
Beta Was this translation helpful? Give feedback.
-
This is nice!!! Anyway, I'd love to see FastAPI supports the BaseModel as well (as per the issue described above) |
Beta Was this translation helpful? Give feedback.
-
|
@iudeen : Nice solution! Do you know, by any chance, why this is working while the 'normal' approach is not? What makes |
Beta Was this translation helpful? Give feedback.
-
|
@JarroVGIT this discussion is about the difference between the two.. |
Beta Was this translation helpful? Give feedback.
-
|
@jerinpetergeorge if you are happy with the solution, you can close this and open a ISSUE/BUG to discuss on why the "normal" approach is not working, and probably finding a better solution! |
Beta Was this translation helpful? Give feedback.
-
I'm kind of okay with the solution since we're still not sure "why" FastAPI doesn't support it - is that on purpose? Or a bug? Also, I hope this current GH issue considers a bug - or I wrote like that in the first place, which makes me think that it is better not to close this GH issue at the moment. I would be super happy if someone could change the label of this issue from https://github.com/tiangolo/fastapi/labels/question to https://github.com/tiangolo/fastapi/labels/bug |
Beta Was this translation helpful? Give feedback.
-
|
Works well in FastAPI 0.115.12 with new query parameter model syntax: import typing
from enum import Enum
from fastapi import FastAPI, Query
from pydantic import BaseModel
app = FastAPI()
class Status(str, Enum):
SUCCESS = "SUCCESS"
REFUND = "REFUND"
FAIL = "FAIL"
CANCEL = "CANCEL"
class StatusModel(BaseModel):
status_in: typing.List[Status]
@app.get("/not-working-example/")
async def root_with_pydantic(status_inputs: StatusModel = Query()):
return {"status_inputs": status_inputs} |
Beta Was this translation helpful? Give feedback.



Works well in FastAPI 0.115.12 with new query parameter model syntax: