committed by
GitHub
1 changed files with 314 additions and 0 deletions
@ -0,0 +1,314 @@ |
|||||
|
# Dateien im Request |
||||
|
|
||||
|
Mit `File` können sie vom Client hochzuladende Dateien definieren. |
||||
|
|
||||
|
!!! info |
||||
|
Um hochgeladene Dateien zu empfangen, installieren Sie zuerst <a href="https://andrew-d.github.io/python-multipart/" class="external-link" target="_blank">`python-multipart`</a>. |
||||
|
|
||||
|
Z. B. `pip install python-multipart`. |
||||
|
|
||||
|
Das, weil hochgeladene Dateien als „Formulardaten“ gesendet werden. |
||||
|
|
||||
|
## `File` importieren |
||||
|
|
||||
|
Importieren Sie `File` und `UploadFile` von `fastapi`: |
||||
|
|
||||
|
=== "Python 3.9+" |
||||
|
|
||||
|
```Python hl_lines="3" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_an_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+" |
||||
|
|
||||
|
```Python hl_lines="1" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_an.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="1" |
||||
|
{!> ../../../docs_src/request_files/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
## `File`-Parameter definieren |
||||
|
|
||||
|
Erstellen Sie Datei-Parameter, so wie Sie es auch mit `Body` und `Form` machen würden: |
||||
|
|
||||
|
=== "Python 3.9+" |
||||
|
|
||||
|
```Python hl_lines="9" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_an_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+" |
||||
|
|
||||
|
```Python hl_lines="8" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_an.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="7" |
||||
|
{!> ../../../docs_src/request_files/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
!!! info |
||||
|
`File` ist eine Klasse, die direkt von `Form` erbt. |
||||
|
|
||||
|
Aber erinnern Sie sich, dass, wenn Sie `Query`, `Path`, `File` und andere von `fastapi` importieren, diese tatsächlich Funktionen sind, welche spezielle Klassen zurückgeben |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Um Dateibodys zu deklarieren, müssen Sie `File` verwenden, da diese Parameter sonst als Query-Parameter oder Body(-JSON)-Parameter interpretiert werden würden. |
||||
|
|
||||
|
Die Dateien werden als „Formulardaten“ hochgeladen. |
||||
|
|
||||
|
Wenn Sie den Typ Ihrer *Pfadoperation-Funktion* als `bytes` deklarieren, wird **FastAPI** die Datei für Sie auslesen, und Sie erhalten den Inhalt als `bytes`. |
||||
|
|
||||
|
Bedenken Sie, dass das bedeutet, dass sich der gesamte Inhalt der Datei im Arbeitsspeicher befindet. Das wird für kleinere Dateien gut funktionieren. |
||||
|
|
||||
|
Aber es gibt viele Fälle, in denen Sie davon profitieren, `UploadFile` zu verwenden. |
||||
|
|
||||
|
## Datei-Parameter mit `UploadFile` |
||||
|
|
||||
|
Definieren Sie einen Datei-Parameter mit dem Typ `UploadFile`: |
||||
|
|
||||
|
=== "Python 3.9+" |
||||
|
|
||||
|
```Python hl_lines="14" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_an_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+" |
||||
|
|
||||
|
```Python hl_lines="13" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_an.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="12" |
||||
|
{!> ../../../docs_src/request_files/tutorial001.py!} |
||||
|
``` |
||||
|
|
||||
|
`UploadFile` zu verwenden, hat mehrere Vorzüge gegenüber `bytes`: |
||||
|
|
||||
|
* Sie müssen `File()` nicht als Parameter-Defaultwert verwenden. |
||||
|
* Es wird eine <abbr title='Aufgespult, Warteschlangenartig'>„Spool“</abbr>-Datei verwendet: |
||||
|
* Eine Datei, die bis zu einem bestimmten Größen-Limit im Arbeitsspeicher behalten wird, und wenn das Limit überschritten wird, auf der Festplatte gespeichert wird. |
||||
|
* Das bedeutet, es wird für große Dateien wie Bilder, Videos, große Binärdateien, usw. gut funktionieren, ohne den ganzen Arbeitsspeicher aufzubrauchen. |
||||
|
* Sie können Metadaten aus der hochgeladenen Datei auslesen. |
||||
|
* Es hat eine <abbr title="dateiartig"><a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a></abbr> `async`hrone Schnittstelle. |
||||
|
* Es stellt ein tatsächliches Python-<abbr title="Warteschlangenartige, temporäre Datei"><a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a></abbr>-Objekt bereit, welches Sie direkt anderen Bibliotheken übergeben können, die ein dateiartiges Objekt erwarten. |
||||
|
|
||||
|
### `UploadFile` |
||||
|
|
||||
|
`UploadFile` hat die folgenden Attribute: |
||||
|
|
||||
|
* `filename`: Ein `str` mit dem ursprünglichen Namen der hochgeladenen Datei (z. B. `meinbild.jpg`). |
||||
|
* `content_type`: Ein `str` mit dem Inhaltstyp (MIME-Typ / Medientyp) (z. B. `image/jpeg`). |
||||
|
* `file`: Ein <a href="https://docs.python.org/3/library/tempfile.html#tempfile.SpooledTemporaryFile" class="external-link" target="_blank">`SpooledTemporaryFile`</a> (ein <a href="https://docs.python.org/3/glossary.html#term-file-like-object" class="external-link" target="_blank">file-like</a> Objekt). Das ist das tatsächliche Python-Objekt, das Sie direkt anderen Funktionen oder Bibliotheken übergeben können, welche ein „file-like“-Objekt erwarten. |
||||
|
|
||||
|
`UploadFile` hat die folgenden `async`hronen Methoden. Sie alle rufen die entsprechenden Methoden des darunterliegenden Datei-Objekts auf (wobei intern `SpooledTemporaryFile` verwendet wird). |
||||
|
|
||||
|
* `write(daten)`: Schreibt `daten` (`str` oder `bytes`) in die Datei. |
||||
|
* `read(anzahl)`: Liest `anzahl` (`int`) bytes/Zeichen aus der Datei. |
||||
|
* `seek(versatz)`: Geht zur Position `versatz` (`int`) in der Datei. |
||||
|
* Z. B. würde `await myfile.seek(0)` zum Anfang der Datei gehen. |
||||
|
* Das ist besonders dann nützlich, wenn Sie `await myfile.read()` einmal ausführen und dann diese Inhalte erneut auslesen müssen. |
||||
|
* `close()`: Schließt die Datei. |
||||
|
|
||||
|
Da alle diese Methoden `async`hron sind, müssen Sie sie `await`en („erwarten“). |
||||
|
|
||||
|
Zum Beispiel können Sie innerhalb einer `async` *Pfadoperation-Funktion* den Inhalt wie folgt auslesen: |
||||
|
|
||||
|
```Python |
||||
|
contents = await myfile.read() |
||||
|
``` |
||||
|
|
||||
|
Wenn Sie sich innerhalb einer normalen `def`-*Pfadoperation-Funktion* befinden, können Sie direkt auf `UploadFile.file` zugreifen, zum Beispiel: |
||||
|
|
||||
|
```Python |
||||
|
contents = myfile.file.read() |
||||
|
``` |
||||
|
|
||||
|
!!! note "Technische Details zu `async`" |
||||
|
Wenn Sie die `async`-Methoden verwenden, führt **FastAPI** die Datei-Methoden in einem <abbr title="Mehrere unabhängige Kindprozesse">Threadpool</abbr> aus und erwartet sie. |
||||
|
|
||||
|
!!! note "Technische Details zu Starlette" |
||||
|
**FastAPI**s `UploadFile` erbt direkt von **Starlette**s `UploadFile`, fügt aber ein paar notwendige Teile hinzu, um es kompatibel mit **Pydantic** und anderen Teilen von FastAPI zu machen. |
||||
|
|
||||
|
## Was sind „Formulardaten“ |
||||
|
|
||||
|
HTML-Formulare (`<form></form>`) senden die Daten in einer „speziellen“ Kodierung zum Server, welche sich von JSON unterscheidet. |
||||
|
|
||||
|
**FastAPI** stellt sicher, dass diese Daten korrekt ausgelesen werden, statt JSON zu erwarten. |
||||
|
|
||||
|
!!! note "Technische Details" |
||||
|
Daten aus Formularen werden, wenn es keine Dateien sind, normalerweise mit dem <abbr title='Media type – Medientyp, Typ des Mediums'>„media type“</abbr> `application/x-www-form-urlencoded` kodiert. |
||||
|
|
||||
|
Sollte das Formular aber Dateien enthalten, dann werden diese mit `multipart/form-data` kodiert. Wenn Sie `File` verwenden, wird **FastAPI** wissen, dass es die Dateien vom korrekten Teil des Bodys holen muss. |
||||
|
|
||||
|
Wenn Sie mehr über Formularfelder und ihre Kodierungen lesen möchten, besuchen Sie die <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST" class="external-link" target="_blank"><abbr title="Mozilla Developer Network – Mozilla-Entwickler-Netzwerk">MDN</abbr>-Webdokumentation für <code>POST</code></a>. |
||||
|
|
||||
|
!!! warning "Achtung" |
||||
|
Sie können mehrere `File`- und `Form`-Parameter in einer *Pfadoperation* deklarieren, aber Sie können nicht gleichzeitig auch `Body`-Felder deklarieren, welche Sie als JSON erwarten, da der Request den Body mittels `multipart/form-data` statt `application/json` kodiert. |
||||
|
|
||||
|
Das ist keine Limitation von **FastAPI**, sondern Teil des HTTP-Protokolls. |
||||
|
|
||||
|
## Optionaler Datei-Upload |
||||
|
|
||||
|
Sie können eine Datei optional machen, indem Sie Standard-Typannotationen verwenden und den Defaultwert auf `None` setzen: |
||||
|
|
||||
|
=== "Python 3.10+" |
||||
|
|
||||
|
```Python hl_lines="9 17" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_02_an_py310.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.9+" |
||||
|
|
||||
|
```Python hl_lines="9 17" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_02_an_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+" |
||||
|
|
||||
|
```Python hl_lines="10 18" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_02_an.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.10+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="7 15" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_02_py310.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="9 17" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_02.py!} |
||||
|
``` |
||||
|
|
||||
|
## `UploadFile` mit zusätzlichen Metadaten |
||||
|
|
||||
|
Sie können auch `File()` zusammen mit `UploadFile` verwenden, um zum Beispiel zusätzliche Metadaten zu setzen: |
||||
|
|
||||
|
=== "Python 3.9+" |
||||
|
|
||||
|
```Python hl_lines="9 15" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_03_an_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+" |
||||
|
|
||||
|
```Python hl_lines="8 14" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_03_an.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="7 13" |
||||
|
{!> ../../../docs_src/request_files/tutorial001_03.py!} |
||||
|
``` |
||||
|
|
||||
|
## Mehrere Datei-Uploads |
||||
|
|
||||
|
Es ist auch möglich, mehrere Dateien gleichzeitig hochzuladen. |
||||
|
|
||||
|
Diese werden demselben Formularfeld zugeordnet, welches mit den Formulardaten gesendet wird. |
||||
|
|
||||
|
Um das zu machen, deklarieren Sie eine Liste von `bytes` oder `UploadFile`s: |
||||
|
|
||||
|
=== "Python 3.9+" |
||||
|
|
||||
|
```Python hl_lines="10 15" |
||||
|
{!> ../../../docs_src/request_files/tutorial002_an_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+" |
||||
|
|
||||
|
```Python hl_lines="11 16" |
||||
|
{!> ../../../docs_src/request_files/tutorial002_an.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.9+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="8 13" |
||||
|
{!> ../../../docs_src/request_files/tutorial002_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="10 15" |
||||
|
{!> ../../../docs_src/request_files/tutorial002.py!} |
||||
|
``` |
||||
|
|
||||
|
Sie erhalten, wie deklariert, eine `list`e von `bytes` oder `UploadFile`s. |
||||
|
|
||||
|
!!! note "Technische Details" |
||||
|
Sie können auch `from starlette.responses import HTMLResponse` verwenden. |
||||
|
|
||||
|
**FastAPI** bietet dieselben `starlette.responses` auch via `fastapi.responses` an, als Annehmlichkeit für Sie, den Entwickler. Die meisten verfügbaren Responses kommen aber direkt von Starlette. |
||||
|
|
||||
|
### Mehrere Datei-Uploads mit zusätzlichen Metadaten |
||||
|
|
||||
|
Und so wie zuvor können Sie `File()` verwenden, um zusätzliche Parameter zu setzen, sogar für `UploadFile`: |
||||
|
|
||||
|
=== "Python 3.9+" |
||||
|
|
||||
|
```Python hl_lines="11 18-20" |
||||
|
{!> ../../../docs_src/request_files/tutorial003_an_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+" |
||||
|
|
||||
|
```Python hl_lines="12 19-21" |
||||
|
{!> ../../../docs_src/request_files/tutorial003_an.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.9+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="9 16" |
||||
|
{!> ../../../docs_src/request_files/tutorial003_py39.py!} |
||||
|
``` |
||||
|
|
||||
|
=== "Python 3.8+ nicht annotiert" |
||||
|
|
||||
|
!!! tip "Tipp" |
||||
|
Bevorzugen Sie die `Annotated`-Version, falls möglich. |
||||
|
|
||||
|
```Python hl_lines="11 18" |
||||
|
{!> ../../../docs_src/request_files/tutorial003.py!} |
||||
|
``` |
||||
|
|
||||
|
## Zusammenfassung |
||||
|
|
||||
|
Verwenden Sie `File`, `bytes` und `UploadFile`, um hochladbare Dateien im Request zu deklarieren, die als Formulardaten gesendet werden. |
Loading…
Reference in new issue