Soy muy nuevo en FastAPI. Quiero validar el tipo de archivo y el tamaño de archivo de un archivo cargado y generar una Exception si está por encima del tamaño y no coincide con el tipo. Este archivo se cargará en S3 Así es como se ve mi código
@router.post("/upload/", status_code=200, description="***** Upload customer document asset to S3 *****") async def upload( document_type: DocumentEnum, customer_id: UUID, current_user=Depends(get_current_user), fileobject: UploadFile = File(...) ): # delete the file from memory and rollover to disk to save unnecessary memory space fileobject.file.rollover() fileobject.file.flush() valid_types = [ 'image/png', 'image/jpeg', 'image/bmp', 'application/pdf' ] await validate_file(fileobject, 5000000, valid_types) # .... Proceed to upload file Mi función validate_file se ve así
async def validate_file(file: UploadFile, max_size: int = None, mime_types: list = None): """ Validate a file by checking the size and mime types aka file types """ if mime_types and file.content_type not in mime_types: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="You can only upload pdf and image for document" ) if max_size: size = await file.read() if len(size) > max_size: raise HTTPException( status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, detail="File size is too big. Limit is 5mb" ) return file Ahora, cuando el archivo se carga en S3 , siempre tiene un tamaño de 0 bytes . Sin embargo, si excluyo la verificación del tamaño del archivo de la función validate_file , entonces el archivo original se carga y no hay problema. Si la función validate_file es así, entonces se carga bien
async def validate_file(file: UploadFile, max_size: int = None, mime_types: list = None): """ Validate a file by checking the size and mime types aka file types """ if mime_types and file.content_type not in mime_types: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, detail="You can only upload pdf and image for document" ) ) return fileNo tengo idea de por qué sucede esto. Gracias de antemano por su ayuda.
Cuando llama a read en un archivo, el puntero del archivo actual estará al final de lo que lee. Cuando usted (o la biblioteca) llame a read por segunda vez, el puntero de archivo interno ya estará al final del archivo.
Puede usar await file.seek(0) para colocar el puntero del archivo al comienzo del archivo, de modo que la próxima lectura lea el mismo contenido nuevamente:
if max_size: size = await file.read() if len(size) > max_size: raise HTTPException( status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, detail="File size is too big. Limit is 5mb" ) await file.seek(0) return file También es posible que desee resolver explícitamente el tipo mime del archivo en lugar de confiar en lo que el usuario dice que es el archivo; puede usar mimetypes.guess_type o algo similar para hacerlo.