Aller au contenu

Envoyer des fichiers

🌐 Traduction par IA et humains

Cette traduction a été réalisée par une IA guidée par des humains. 🤝

Elle peut contenir des erreurs d'interprétation du sens original, ou paraître peu naturelle, etc. 🤖

Vous pouvez améliorer cette traduction en nous aidant à mieux guider le LLM d'IA.

Version anglaise

Vous pouvez définir des fichiers à téléverser par le client en utilisant File.

Info

Pour recevoir des fichiers téléversés, installez d'abord python-multipart.

Assurez-vous de créer un environnement virtuel, de l'activer, puis d'installer le paquet, par exemple :

$ pip install python-multipart

C'est parce que les fichiers téléversés sont envoyés en « données de formulaire ».

Importer File

Importez File et UploadFile depuis fastapi :

from typing import Annotated

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: Annotated[bytes, File()]):
    return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    return {"filename": file.filename}
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: bytes = File()):
    return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    return {"filename": file.filename}

Définir des paramètres File

Créez des paramètres de fichier de la même manière que pour Body ou Form :

from typing import Annotated

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: Annotated[bytes, File()]):
    return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    return {"filename": file.filename}
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: bytes = File()):
    return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    return {"filename": file.filename}

Info

File est une classe qui hérite directement de Form.

Mais souvenez-vous que lorsque vous importez Query, Path, File et d'autres depuis fastapi, ce sont en réalité des fonctions qui renvoient des classes spéciales.

Astuce

Pour déclarer des fichiers dans le corps de la requête, vous devez utiliser File, sinon les paramètres seraient interprétés comme des paramètres de requête ou des paramètres de corps (JSON).

Les fichiers seront téléversés en « données de formulaire ».

Si vous déclarez le type de votre paramètre de fonction de chemin d'accès comme bytes, FastAPI lira le fichier pour vous et vous recevrez le contenu sous forme de bytes.

Gardez à l'esprit que cela signifie que tout le contenu sera stocké en mémoire. Cela fonctionnera bien pour de petits fichiers.

Mais dans plusieurs cas, vous pourriez bénéficier de l'utilisation d'UploadFile.

Paramètres de fichier avec UploadFile

Définissez un paramètre de fichier de type UploadFile :

from typing import Annotated

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: Annotated[bytes, File()]):
    return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    return {"filename": file.filename}
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: bytes = File()):
    return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
    return {"filename": file.filename}

Utiliser UploadFile présente plusieurs avantages par rapport à bytes :

  • Vous n'avez pas besoin d'utiliser File() comme valeur par défaut du paramètre.
  • Il utilise un fichier « spooled » :
    • Un fichier stocké en mémoire jusqu'à une taille maximale, puis, au-delà de cette limite, stocké sur le disque.
  • Cela fonctionne donc bien pour des fichiers volumineux comme des images, des vidéos, de gros binaires, etc., sans consommer toute la mémoire.
  • Vous pouvez obtenir des métadonnées à partir du fichier téléversé.
  • Il offre une interface async de type file-like.
  • Il expose un véritable objet Python SpooledTemporaryFile que vous pouvez passer directement à d'autres bibliothèques qui attendent un objet « file-like ».

UploadFile

UploadFile a les attributs suivants :

  • filename : une str contenant le nom de fichier original téléversé (par ex. myimage.jpg).
  • content_type : une str avec le type de contenu (type MIME / type média) (par ex. image/jpeg).
  • file : un SpooledTemporaryFile (un objet de type fichier). C'est l'objet fichier Python réel que vous pouvez passer directement à d'autres fonctions ou bibliothèques qui attendent un objet « file-like ».

UploadFile a les méthodes async suivantes. Elles appellent toutes les méthodes correspondantes du fichier sous-jacent (en utilisant le SpooledTemporaryFile interne).

  • write(data) : écrit data (str ou bytes) dans le fichier.
  • read(size) : lit size (int) octets/caractères du fichier.
  • seek(offset) : se déplace à la position d'octet offset (int) dans le fichier.
    • Par ex., await myfile.seek(0) irait au début du fichier.
    • C'est particulièrement utile si vous exécutez await myfile.read() une fois puis devez relire le contenu.
  • close() : ferme le fichier.

Comme toutes ces méthodes sont async, vous devez les « await ».

Par exemple, à l'intérieur d'une fonction de chemin d'accès async, vous pouvez obtenir le contenu avec :

contents = await myfile.read()

Si vous êtes dans une fonction de chemin d'accès def normale, vous pouvez accéder directement à UploadFile.file, par exemple :

contents = myfile.file.read()

Détails techniques async

Lorsque vous utilisez les méthodes async, FastAPI exécute les méthodes de fichier dans un pool de threads et les attend.

Détails techniques Starlette

L'UploadFile de FastAPI hérite directement de l'UploadFile de Starlette, mais ajoute certaines parties nécessaires pour le rendre compatible avec Pydantic et les autres parties de FastAPI.

Qu'est-ce que les « données de formulaire »

La façon dont les formulaires HTML (<form></form>) envoient les données au serveur utilise normalement un encodage « spécial » pour ces données, différent de JSON.

FastAPI s'assure de lire ces données au bon endroit plutôt que depuis JSON.

Détails techniques

Les données des formulaires sont normalement encodées avec le « type de média » application/x-www-form-urlencoded lorsqu'elles n'incluent pas de fichiers.

Mais lorsque le formulaire inclut des fichiers, il est encodé en multipart/form-data. Si vous utilisez File, FastAPI saura qu'il doit récupérer les fichiers depuis la partie appropriée du corps.

Si vous souhaitez en savoir plus sur ces encodages et les champs de formulaire, consultez la MDN Web Docs pour POST.

Alertes

Vous pouvez déclarer plusieurs paramètres File et Form dans un chemin d'accès, mais vous ne pouvez pas également déclarer des champs Body que vous vous attendez à recevoir en JSON, car la requête aura le corps encodé en multipart/form-data au lieu de application/json.

Ce n'est pas une limitation de FastAPI, cela fait partie du protocole HTTP.

Téléversement de fichier facultatif

Vous pouvez rendre un fichier facultatif en utilisant des annotations de type standard et en définissant une valeur par défaut à None :

from typing import Annotated

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: Annotated[bytes | None, File()] = None):
    if not file:
        return {"message": "No file sent"}
    else:
        return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile | None = None):
    if not file:
        return {"message": "No upload file sent"}
    else:
        return {"filename": file.filename}
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: bytes | None = File(default=None)):
    if not file:
        return {"message": "No file sent"}
    else:
        return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile | None = None):
    if not file:
        return {"message": "No upload file sent"}
    else:
        return {"filename": file.filename}

UploadFile avec des métadonnées supplémentaires

Vous pouvez aussi utiliser File() avec UploadFile, par exemple pour définir des métadonnées supplémentaires :

from typing import Annotated

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: Annotated[bytes, File(description="A file read as bytes")]):
    return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(
    file: Annotated[UploadFile, File(description="A file read as UploadFile")],
):
    return {"filename": file.filename}
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import FastAPI, File, UploadFile

app = FastAPI()


@app.post("/files/")
async def create_file(file: bytes = File(description="A file read as bytes")):
    return {"file_size": len(file)}


@app.post("/uploadfile/")
async def create_upload_file(
    file: UploadFile = File(description="A file read as UploadFile"),
):
    return {"filename": file.filename}

Téléverser plusieurs fichiers

Il est possible de téléverser plusieurs fichiers en même temps.

Ils seraient associés au même « champ de formulaire » envoyé en « données de formulaire ».

Pour cela, déclarez une list de bytes ou d'UploadFile :

from typing import Annotated

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse

app = FastAPI()


@app.post("/files/")
async def create_files(files: Annotated[list[bytes], File()]):
    return {"file_sizes": [len(file) for file in files]}


@app.post("/uploadfiles/")
async def create_upload_files(files: list[UploadFile]):
    return {"filenames": [file.filename for file in files]}


@app.get("/")
async def main():
    content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
    """
    return HTMLResponse(content=content)
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse

app = FastAPI()


@app.post("/files/")
async def create_files(files: list[bytes] = File()):
    return {"file_sizes": [len(file) for file in files]}


@app.post("/uploadfiles/")
async def create_upload_files(files: list[UploadFile]):
    return {"filenames": [file.filename for file in files]}


@app.get("/")
async def main():
    content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
    """
    return HTMLResponse(content=content)

Vous recevrez, comme déclaré, une list de bytes ou d'UploadFile.

Détails techniques

Vous pourriez aussi utiliser from starlette.responses import HTMLResponse.

FastAPI fournit les mêmes starlette.responses sous fastapi.responses simplement pour votre convenance en tant que développeur. Mais la plupart des réponses disponibles proviennent directement de Starlette.

Téléversements multiples avec métadonnées supplémentaires

Et de la même manière que précédemment, vous pouvez utiliser File() pour définir des paramètres supplémentaires, même pour UploadFile :

from typing import Annotated

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse

app = FastAPI()


@app.post("/files/")
async def create_files(
    files: Annotated[list[bytes], File(description="Multiple files as bytes")],
):
    return {"file_sizes": [len(file) for file in files]}


@app.post("/uploadfiles/")
async def create_upload_files(
    files: Annotated[
        list[UploadFile], File(description="Multiple files as UploadFile")
    ],
):
    return {"filenames": [file.filename for file in files]}


@app.get("/")
async def main():
    content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
    """
    return HTMLResponse(content=content)
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse

app = FastAPI()


@app.post("/files/")
async def create_files(
    files: list[bytes] = File(description="Multiple files as bytes"),
):
    return {"file_sizes": [len(file) for file in files]}


@app.post("/uploadfiles/")
async def create_upload_files(
    files: list[UploadFile] = File(description="Multiple files as UploadFile"),
):
    return {"filenames": [file.filename for file in files]}


@app.get("/")
async def main():
    content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
    """
    return HTMLResponse(content=content)

Récapitulatif

Utilisez File, bytes et UploadFile pour déclarer des fichiers à téléverser dans la requête, envoyés en « données de formulaire ».