Here's a self-contained, minimal, reproducible, example with my use case:
from fastapi import FastAPI, File, UploadFile
from pydantic import BaseModel
app = FastAPI()
class Properties(BaseModel):
language: str = None
author: str = None
@app.post("/uploadfile/", status_code=201)
async def create_upload_file(properties: Properties, file: UploadFile = File(...)):
return {"filename": file.filename, 'properties': properties}
/docs and call the endpoint /uploadfile.Immediately I apologize, maybe I missed something and / or did not understand and should not have bothered you. I need this function in order to unload a poster for it along with information in the form of a Pydantic model. I issued a patch, but everyone ignores it
based on docs
from fastapi import FastAPI, File, UploadFile,Form
from pydantic import BaseModel
app = FastAPI()
class Properties(BaseModel):
language: str = None
author: str = None
@app.post("/uploadfile/", status_code=201)
async def create_upload_file(language: str = Form(...),author: str = Form(...),file: UploadFile = File(...)):
return {"filename": file.filename, 'properties': Properties(language=language,author=author)}
based on docs
from fastapi import FastAPI, File, UploadFile,Form from pydantic import BaseModel app = FastAPI() class Properties(BaseModel): language: str = None author: str = None @app.post("/uploadfile/", status_code=201) async def create_upload_file(language: str = Form(...),author: str = Form(...),file: UploadFile = File(...)): return {"filename": file.filename, 'properties': Properties(language=language,author=author)}
Hello. This option does not suit me, since the model in my project has many fields and I do not want crutches in my project, because of this I released a patch so that you can transfer the Pydantic Model to FormData. But thanks for trying to help
Then you can try to use dependency injection. Just make class with required fields (better use dataclass).
But imo it's bad practice to upload file and body fields simultaneously
Then you can try to use dependency injection. Just make class with required fields (better use dataclass).
Again, this will be a crutch, I already have a ready-made Pydantic model and a handler for it. Now I just want to add a picture to it. FastAPI does not support the Pydantic model through FormData. Why can't you just add support for this? I already solved this problem with 4 lines of code but they are ignored. But thanks for trying to help
Again, this will be a crutch, I already have a ready-made Pydantic model and a handler for it. Now I just want to add a picture to it. FastAPI does not support the Pydantic model through FormData. Why can't you just add support for this? I already solved this problem with 4 lines of code but they are ignored. But thanks for trying to help
In fact, it's working with Pydantic model, I had such code snippet in my pet project:
@api.post('/')
def add_review(
body: Model = Body(...),
image_files: Optional[List[UploadFile]] = File(None, media_type='image/jpeg'),
):
...
BUT! when I tried to send such data I had to insert body json as string inside form-data (that's RFC limitations: https://tools.ietf.org/html/rfc1867)
In fact, it's working with Pydantic model, I had such code snippet in my pet project:
@api.post('/') def add_review( body: Model = Body(...), image_files: Optional[List[UploadFile]] = File(None, media_type='image/jpeg'), ): ...BUT! when I tried to send such data I had to insert body json as string inside form-data (that's RFC limitations: https://tools.ietf.org/html/rfc1867)
The code you provided doesn't work ("Model" in your example inherits the Pydantic model right?) (At least with Swagger). Error 422 (Swagger still submits the Pydantic model via form data and this cannot be handled by FastAPI). And if this does not work in Swagger, then I cannot make tests for my project (pytest)
@app.post("/uploadfile", status_code=201)
async def create_upload_file(properties: Properties = Form(...), file: UploadFile = File(...)):
return {"filename": file.filename, 'properties': properties}
We left on the wrong topic. I want to discuss why I cannot use FormData
Oups, sorry, I forgot I made custom validator to transform str to json for Model:
class Model(BaseModel):
foo: int
bar: str
@classmethod
def __get_validators__(cls):
yield cls.validate_to_json
@classmethod
def validate_to_json(cls, value):
if isinstance(value, str):
return cls(**json.loads(value))
return value
Oups, sorry, I forgot I made custom validator to transform str to json for Model:
class Model(BaseModel): foo: int bar: str @classmethod def __get_validators__(cls): yield cls.validate_to_json @classmethod def validate_to_json(cls, value): if isinstance(value, str): return cls(**json.loads(value)) return value
I've seen a similar solution, but you don't think it is a workaround. Maybe it's time to really fix the problem? You can try using my fork with the problem fixed
We left on the wrong topic. I want to discuss why I cannot use FormData
I can't give you answer, but I think it's because Form data is string and cannot be parsed easily. For example, you cannot use Pydantic model in Query too, only for Body params
Мы ушли не по той теме. Я хочу обсудить, почему я не могу использовать FormData
Я не могу дать вам ответ, но думаю, это потому, что данные формы являются строковыми и не могут быть легко проанализированы. Например, вы не можете использовать модель Pydantic в Query, только для параметров Body.
Imo it's still workaround and even dirtier than custom validator. Form Data used for text and files commonly, not for json data and making it as default behavior could be misleading and make more bugs.
As I said, look at Form like at Query, they share identical behavior - some small atomic data
Still, it could be my stubbornness and I'd like to hear another one opinion
Imo it's still workaround and even dirtier than custom validator. Form Data used for text and files commonly, not for json data and making it as default behavior could be misleading and make more bugs.
As I said, look at Form like at Query, they share identical behavior - some small atomic data
Still, it could be my stubbornness and I'd like to hear another one opinion
Perhaps you are right, we will wait for opinions on this from other participants.
A small digression. I am currently switching from Django there it uses Form to pass new record data. Why the same cannot be done in FastAPI. It's just a question
Hi,
if I understand you well you can use UploadFile and Pydantic model in one request using Dependencies.
More detailed information here: https://fastapi.tiangolo.com/tutorial/dependencies/
Sample code:
from fastapi import File, UploadFile, Depends
class User(BaseModel):
username: str
password: str
@app.post('/user')
async def upload(user: User = Depends(), file: UploadFile = File(...)):
data_db = user.dict()
print(data_db)
Hi,
if I understand you well you can use UploadFile and Pydantic model in one request using Dependencies.
More detailed information here: https://fastapi.tiangolo.com/tutorial/dependencies/
Sample code:from fastapi import File, UploadFile, Depends class User(BaseModel): username: str password: str @app.post('/user') async def upload(user: User = Depends(), file: UploadFile = File(...)): data_db = user.dict() print(data_db)
Hello. Thanks for trying to help, but that's not what I want. My pidantic model is quite large and it's not very good to use GET parameters for it. I think it is better to use custom validator in pydantic model and pass data through FormData. I think it's time to close this topic
Oups, sorry, I forgot I made custom validator to transform str to json for Model:
class Model(BaseModel): foo: int bar: str @classmethod def __get_validators__(cls): yield cls.validate_to_json @classmethod def validate_to_json(cls, value): if isinstance(value, str): return cls(**json.loads(value)) return value
This is the solution to the problem. But it would be better if you can use the pydantic model through FormData without additional code. There is a ready-made patch for this problem