From 602f8c240698715cb0171ae1646df51c95fe842d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebasti=C3=A1n=20Ram=C3=ADrez?= Date: Sat, 26 Jul 2025 22:37:48 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Add=20additional=20new=20German?= =?UTF-8?q?=20translations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/de/docs/how-to/testing-database.md | 7 + docs/de/docs/tutorial/cookie-param-models.md | 76 ++++ docs/de/docs/tutorial/debugging.md | 113 ++++++ docs/de/docs/tutorial/header-param-models.md | 72 ++++ docs/de/docs/tutorial/query-param-models.md | 68 ++++ docs/de/docs/tutorial/sql-databases.md | 357 +++++++++++++++++++ 6 files changed, 693 insertions(+) create mode 100644 docs/de/docs/how-to/testing-database.md create mode 100644 docs/de/docs/tutorial/cookie-param-models.md create mode 100644 docs/de/docs/tutorial/debugging.md create mode 100644 docs/de/docs/tutorial/header-param-models.md create mode 100644 docs/de/docs/tutorial/query-param-models.md create mode 100644 docs/de/docs/tutorial/sql-databases.md diff --git a/docs/de/docs/how-to/testing-database.md b/docs/de/docs/how-to/testing-database.md new file mode 100644 index 000000000..c556fbf31 --- /dev/null +++ b/docs/de/docs/how-to/testing-database.md @@ -0,0 +1,7 @@ +# Testen einer Datenbank + +Sie können mehr über Datenbanken, SQL und SQLModel in den SQLModel-Dokumentationen lernen. 🤓 + +Es gibt ein Mini-Tutorial zur Verwendung von SQLModel mit FastAPI. ✨ + +Dieses Tutorial enthält einen Abschnitt über das Testen von SQL-Datenbanken. 😎 diff --git a/docs/de/docs/tutorial/cookie-param-models.md b/docs/de/docs/tutorial/cookie-param-models.md new file mode 100644 index 000000000..31f21775b --- /dev/null +++ b/docs/de/docs/tutorial/cookie-param-models.md @@ -0,0 +1,76 @@ +# Cookie-Parameter-Modelle + +Wenn Sie eine Gruppe von **Cookies** haben, die zusammengehören, können Sie ein **Pydantic-Modell** erstellen, um sie zu deklarieren. 🍪 + +Dies ermöglicht es Ihnen, das **Modell** an **mehreren Stellen wiederzuverwenden** und auch Validierungen und Metadaten für alle Parameter auf einmal zu deklarieren. 😎 + +/// note | Hinweis + +Dies wird seit der FastAPI-Version `0.115.0` unterstützt. 🤓 + +/// + +/// tip | Tipp + +Diese Technik funktioniert genauso für `Query`, `Cookie` und `Header`. 😎 + +/// + +## Cookies mit einem Pydantic-Modell + +Deklarieren Sie die benötigten **Cookie**-Parameter in einem **Pydantic-Modell**, und deklarieren Sie dann den Parameter als `Cookie`: + +{* ../../docs_src/cookie_param_models/tutorial001_an_py310.py hl[9:12,16] *} + +**FastAPI** wird die Daten für **jedes Feld** aus den in der Anfrage erhaltenen **Cookies** extrahieren und Ihnen das von Ihnen definierte Pydantic-Modell bereitstellen. + +## Überprüfen Sie die Dokumentation + +Sie können die definierten Cookies in der Docs-Oberfläche unter `/docs` sehen: + +
+ +
+ +/// info | Hinweis + +Berücksichtigen Sie, dass **Browser Cookies** auf spezielle Weise und im Hintergrund handhaben und sie **JavaScript** nicht leicht erlauben, diese zu berühren. + +Wenn Sie zur **API-Dokumentations-Oberfläche** unter `/docs` gehen, können Sie die **Dokumentation** für Cookies für Ihre *Pfadoperationen* sehen. + +Aber selbst wenn Sie die **Daten ausfüllen** und auf "Ausführen" klicken, werden die Cookies nicht gesendet, da die Docs-Oberfläche mit **JavaScript** arbeitet, und Sie erhalten eine **Fehlermeldung**, als ob Sie keine Werte eingegeben hätten. + +/// + +## Zusätzliche Cookies verbieten + +In einigen speziellen Anwendungsfällen (vermutlich nicht sehr häufig) möchten Sie möglicherweise die Cookies, die Sie erhalten möchten, **einschränken**. + +Ihre API hat jetzt die Macht, ihre eigene Cookie-Zustimmung zu kontrollieren. 🤪🍪 + +Sie können die Modellkonfiguration von Pydantic verwenden, um alle `extra` Felder zu `verbieten`: + +{* ../../docs_src/cookie_param_models/tutorial002_an_py39.py hl[10] *} + +Wenn ein Client versucht, einige **zusätzliche Cookies** zu senden, erhält er eine **Error-Response**. + +Arme Cookie-Banner mit all ihrer Mühe, Ihre Zustimmung für die API zu bekommen, um sie abzulehnen. 🍪 + +Wenn der Client beispielsweise versucht, ein `santa_tracker`-Cookie mit dem Wert `good-list-please` zu senden, erhält der Client eine **Error-Response**, die ihm mitteilt, dass das `santa_tracker`-Cookie nicht erlaubt ist: + +```json +{ + "detail": [ + { + "type": "extra_forbidden", + "loc": ["cookie", "santa_tracker"], + "msg": "Extra inputs are not permitted", + "input": "good-list-please", + } + ] +} +``` + +## Zusammenfassung + +Sie können **Pydantic-Modelle** verwenden, um **Cookies** in **FastAPI** zu deklarieren. 😎 diff --git a/docs/de/docs/tutorial/debugging.md b/docs/de/docs/tutorial/debugging.md new file mode 100644 index 000000000..74df8d20e --- /dev/null +++ b/docs/de/docs/tutorial/debugging.md @@ -0,0 +1,113 @@ +# Debugging + +Sie können den Debugger in Ihrem Editor verbinden, zum Beispiel mit Visual Studio Code oder PyCharm. + +## Aufruf von `uvicorn` + +Importieren und führen Sie `uvicorn` direkt in Ihrer FastAPI-Anwendung aus: + +{* ../../docs_src/debugging/tutorial001.py hl[1,15] *} + +### Über `__name__ == "__main__"` + +Der Hauptzweck von `__name__ == "__main__"` ist, dass bestimmter Code ausgeführt wird, wenn Ihre Datei mit: + +
+ +```console +$ python myapp.py +``` + +
+ +aufgerufen wird, aber nicht ausgeführt wird, wenn eine andere Datei sie importiert, wie in: + +```Python +from myapp import app +``` + +#### Mehr Details + +Angenommen, Ihre Datei heißt `myapp.py`. + +Wenn Sie sie mit: + +
+ +```console +$ python myapp.py +``` + +
+ +ausführen, hat die interne Variable `__name__` in Ihrer Datei, die automatisch von Python erstellt wird, den Wert der Zeichenkette `"__main__"`. + +Also wird der Abschnitt: + +```Python + uvicorn.run(app, host="0.0.0.0", port=8000) +``` + +ausgeführt. + +--- + +Das wird nicht passieren, wenn Sie dieses Modul (Datei) importieren. + +Wenn Sie also eine andere Datei `importer.py` mit folgendem Inhalt haben: + +```Python +from myapp import app + +# Weiterer Code +``` + +wird in diesem Fall die automatisch erstellte Variable innerhalb von `myapp.py` nicht den Wert `"__main__"` für die Variable `__name__` haben. + +Daher wird die Zeile: + +```Python + uvicorn.run(app, host="0.0.0.0", port=8000) +``` + +nicht ausgeführt. + +/// info | Hinweis + +Für weitere Informationen schauen Sie in die offiziellen Python-Dokumentationen. + +/// + +## Führen Sie Ihren Code mit Ihrem Debugger aus + +Da Sie den Uvicorn-Server direkt aus Ihrem Code heraus ausführen, können Sie Ihr Python-Programm (Ihre FastAPI-Anwendung) direkt aus dem Debugger aufrufen. + +--- + +Zum Beispiel können Sie in Visual Studio Code: + +* Zum "Debug"-Panel gehen. +* "Konfiguration hinzufügen..." wählen. +* "Python" auswählen. +* Den Debugger mit der Option "`Python: Current File (Integrated Terminal)`" ausführen. + +Damit wird dann der Server mit Ihrem **FastAPI**-Code gestartet, an Ihren Breakpoints angehalten usw. + +So könnte es aussehen: + + + +--- + +Wenn Sie Pycharm verwenden, können Sie: + +* Das "Run"-Menü öffnen. +* Die Option "Debug..." auswählen. +* Es erscheint ein Kontextmenü. +* Die Datei zum Debuggen auswählen (in diesem Fall `main.py`). + +Damit wird dann der Server mit Ihrem **FastAPI**-Code gestartet, an Ihren Breakpoints angehalten usw. + +So könnte es aussehen: + + diff --git a/docs/de/docs/tutorial/header-param-models.md b/docs/de/docs/tutorial/header-param-models.md new file mode 100644 index 000000000..08c011be0 --- /dev/null +++ b/docs/de/docs/tutorial/header-param-models.md @@ -0,0 +1,72 @@ +# Header-Parameter-Modelle + +Wenn Sie eine Gruppe von verwandten **Header-Parametern** haben, können Sie ein **Pydantic-Modell** erstellen, um diese zu deklarieren. + +Dies ermöglicht es Ihnen, das **Modell wiederzuverwenden** in **mehreren Stellen** und auch Validierungen und Metadaten für alle Parameter auf einmal zu deklarieren. 😎 + +/// note | Hinweis + +Dies wird seit FastAPI-Version `0.115.0` unterstützt. 🤓 + +/// + +## Header-Parameter mit einem Pydantic-Modell + +Deklarieren Sie die **Header-Parameter**, die Sie benötigen, in einem **Pydantic-Modell** und dann den Parameter als `Header`: + +{* ../../docs_src/header_param_models/tutorial001_an_py310.py hl[9:14,18] *} + +**FastAPI** wird die Daten für **jedes Feld** aus den **Headers** in der Anfrage **extrahieren** und Ihnen das definierte Pydantic-Modell übergeben. + +## Überprüfen Sie die Dokumentation + +Sie können die erforderlichen Headers in der Dokumentationsoberfläche unter `/docs` sehen: + +
+ +
+ +## Zusätzliche Headers verbieten + +In einigen speziellen Anwendungsfällen (wahrscheinlich nicht sehr häufig) möchten Sie möglicherweise die **Headers einschränken**, die Sie empfangen möchten. + +Sie können die Modellkonfiguration von Pydantic verwenden, um `zusätzliche` Felder zu `verbieten`: + +{* ../../docs_src/header_param_models/tutorial002_an_py310.py hl[10] *} + +Wenn ein Client versucht, einige **zusätzliche Headers** zu senden, erhalten sie eine **Error-Response**. + +Zum Beispiel, wenn der Client versucht, einen `tool`-Header mit dem Wert `plumbus` zu senden, erhalten sie eine **Error-Response**, die ihnen mitteilt, dass der Header-Parameter `tool` nicht erlaubt ist: + +```json +{ + "detail": [ + { + "type": "extra_forbidden", + "loc": ["header", "tool"], + "msg": "Extra inputs are not permitted", + "input": "plumbus", + } + ] +} +``` + +## Automatische Konvertierung von Unterstrichen deaktivieren + +Genauso wie bei regulären Header-Parametern, werden bei der Verwendung von Unterstrich-Zeichen in den Parameternamen diese **automatisch in Bindestriche umgewandelt**. + +Zum Beispiel, wenn Sie einen Header-Parameter `save_data` im Code haben, wird der erwartete HTTP-Header `save-data` sein, und er wird auch so in der Dokumentation erscheinen. + +Wenn Sie aus irgendeinem Grund diese automatische Konvertierung deaktivieren müssen, können Sie dies auch für Pydantic-Modelle für Header-Parameter tun. + +{* ../../docs_src/header_param_models/tutorial003_an_py310.py hl[19] *} + +/// warning | Achtung + +Bevor Sie `convert_underscores` auf `False` setzen, bedenken Sie, dass einige HTTP-Proxies und Server die Verwendung von Headers mit Unterstrichen nicht zulassen. + +/// + +## Zusammenfassung + +Sie können **Pydantic-Modelle** verwenden, um **Headers** in **FastAPI** zu deklarieren. 😎 diff --git a/docs/de/docs/tutorial/query-param-models.md b/docs/de/docs/tutorial/query-param-models.md new file mode 100644 index 000000000..973df7a9c --- /dev/null +++ b/docs/de/docs/tutorial/query-param-models.md @@ -0,0 +1,68 @@ +# Query-Parameter-Modelle + +Wenn Sie eine Gruppe von **Query-Parametern** haben, die in Zusammenhang stehen, können Sie ein **Pydantic-Modell** erstellen, um sie zu deklarieren. + +Dadurch können Sie das **Modell** an **mehreren Stellen wiederverwenden** und auch Validierungen und Metadaten für alle Parameter auf einmal deklarieren. 😎 + +/// note | Hinweis + +Dies wird seit FastAPI-Version `0.115.0` unterstützt. 🤓 + +/// + +## Query-Parameter mit einem Pydantic-Modell + +Deklarieren Sie die benötigten **Query-Parameter** in einem **Pydantic-Modell** und deklarieren Sie dann den Parameter als `Query`: + +{* ../../docs_src/query_param_models/tutorial001_an_py310.py hl[9:13,17] *} + +**FastAPI** wird die Daten für **jedes Feld** aus den **Query-Parametern** der Anfrage **extrahieren** und Ihnen das von Ihnen definierte Pydantic-Modell übergeben. + +## Überprüfen Sie die Dokumentation + +Sie können die Query-Parameter in der Dokumentationsoberfläche unter `/docs` sehen: + +
+ +
+ +## Zusätzliche Query-Parameter verbieten + +In einigen speziellen Anwendungsfällen (wahrscheinlich nicht sehr häufig) möchten Sie möglicherweise die Query-Parameter, die Sie empfangen möchten, **einschränken**. + +Sie können die Modellkonfiguration von Pydantic verwenden, um `extra` Felder zu `verbieten`: + +{* ../../docs_src/query_param_models/tutorial002_an_py310.py hl[10] *} + +Wenn ein Client versucht, einige **zusätzliche** Daten in den **Query-Parametern** zu senden, erhält er eine **Error-Response**. + +Wenn der Client beispielsweise versucht, einen `tool` Query-Parameter mit einem Wert von `plumbus` zu senden, wie: + +```http +https://example.com/items/?limit=10&tool=plumbus +``` + +wird er eine **Error-Response** erhalten, die ihm mitteilt, dass der Query-Parameter `tool` nicht erlaubt ist: + +```json +{ + "detail": [ + { + "type": "extra_forbidden", + "loc": ["query", "tool"], + "msg": "Extra inputs are not permitted", + "input": "plumbus" + } + ] +} +``` + +## Zusammenfassung + +Sie können **Pydantic-Modelle** verwenden, um **Query-Parameter** in **FastAPI** zu deklarieren. 😎 + +/// tip | Tipp + +Spoiler-Alarm: Sie können auch Pydantic-Modelle verwenden, um Cookies und Header zu deklarieren, aber darüber werden Sie später im Tutorial lesen. 🤫 + +/// diff --git a/docs/de/docs/tutorial/sql-databases.md b/docs/de/docs/tutorial/sql-databases.md new file mode 100644 index 000000000..f17f74788 --- /dev/null +++ b/docs/de/docs/tutorial/sql-databases.md @@ -0,0 +1,357 @@ +# SQL (Relationale) Datenbanken + +**FastAPI** erfordert nicht, dass Sie eine SQL (relationale) Datenbank verwenden. Aber Sie können **jede beliebige Datenbank** verwenden, die Sie möchten. + +Hier werden wir ein Beispiel mit SQLModel sehen. + +**SQLModel** basiert auf SQLAlchemy und Pydantic. Es wurde vom selben Autor wie **FastAPI** entwickelt, um die perfekte Ergänzung für FastAPI-Anwendungen zu sein, die **SQL-Datenbanken** verwenden müssen. + +/// tip | Tipp + +Sie könnten jede andere SQL- oder NoSQL-Datenbankbibliothek verwenden, die Sie möchten (in einigen Fällen als „ORMs“ bezeichnet), FastAPI zwingt Sie nicht, irgendetwas zu verwenden. 😎 + +/// + +Da SQLModel auf SQLAlchemy basiert, können Sie problemlos **jede von SQLAlchemy unterstützte Datenbank** verwenden (was auch bedeutet, dass sie von SQLModel unterstützt werden), wie: + +* PostgreSQL +* MySQL +* SQLite +* Oracle +* Microsoft SQL Server usw. + +In diesem Beispiel verwenden wir **SQLite**, da es eine einzige Datei verwendet und Python integrierte Unterstützung bietet. Sie können dieses Beispiel kopieren und direkt so ausführen. + +Später, für Ihre Produktionsanwendung, möchten Sie möglicherweise einen Datenbankserver wie **PostgreSQL** verwenden. + +/// tip | Tipp + +Es gibt einen offiziellen Projektgenerator mit **FastAPI** und **PostgreSQL**, einschließlich eines Frontends und weiterer Tools: https://github.com/fastapi/full-stack-fastapi-template + +/// + +Dies ist ein sehr einfaches und kurzes Tutorial. Wenn Sie mehr über Datenbanken im Allgemeinen, über SQL oder fortgeschrittenere Funktionen erfahren möchten, gehen Sie zu den SQLModel-Dokumentationen. + +## Installieren Sie `SQLModel` + +Stellen Sie zunächst sicher, dass Sie Ihre [virtuelle Umgebung](../virtual-environments.md){.internal-link target=_blank} erstellen, sie aktivieren und dann `sqlmodel` installieren: + +
+ +```console +$ pip install sqlmodel +---> 100% +``` + +
+ +## Erstellen Sie die Anwendung mit einem einzigen Modell + +Wir erstellen zuerst die einfachste erste Version der Anwendung mit einem einzigen **SQLModel**-Modell. + +Später werden wir sie verbessern, indem wir die Sicherheit und die Vielseitigkeit mit **mehreren Modellen** weiter unten erhöhen. 🤓 + +### Modelle erstellen + +Importieren Sie `SQLModel` und erstellen Sie ein Datenbankmodell: + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[1:11] hl[7:11] *} + +Die `Hero`-Klasse ist einem Pydantic-Modell sehr ähnlich (tatsächlich ist sie darunter tatsächlich *ein Pydantic-Modell*). + +Es gibt einige Unterschiede: + +* `table=True` sagt SQLModel, dass dies ein *Tabellenmodell* ist, es soll eine **Tabelle** in der SQL-Datenbank darstellen, es ist nicht nur ein *Datenmodell* (wie es jede andere reguläre Pydantic-Klasse wäre). + +* `Field(primary_key=True)` sagt SQLModel, dass die `id` der **Primärschlüssel** in der SQL-Datenbank ist (Sie können mehr über SQL-Primärschlüssel in den SQLModel-Dokumentationen erfahren). + + Durch das Festlegen des Typs als `int | None` wird SQLModel wissen, dass diese Spalte ein `INTEGER` in der SQL-Datenbank sein sollte und dass sie `NULLABLE` sein sollte. + +* `Field(index=True)` sagt SQLModel, dass es einen **SQL-Index** für diese Spalte erstellen soll, der schnellere Lookups in der Datenbank ermöglicht, wenn Daten durch diese Spalte gefiltert gelesen werden. + + SQLModel wird verstehen, dass etwas, das als `str` deklariert ist, eine SQL-Spalte des Typs `TEXT` (oder `VARCHAR`, abhängig von der Datenbank) sein wird. + +### Erstellen Sie einen Engine + +Eine SQLModel `engine` (darunter ist es tatsächlich eine SQLAlchemy `engine`) ist das, was die **Verbindungen** zur Datenbank hält. + +Sie würden **ein einzelnes `engine`-Objekt** für Ihren gesamten Code verwenden, um sich mit demselben Datenbank zu verbinden. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[14:18] hl[14:15,17:18] *} + +Die Verwendung von `check_same_thread=False` erlaubt FastAPI, dieselbe SQLite-Datenbank in verschiedenen Threads zu verwenden. Dies ist notwendig, da **eine einzige Anfrage** **mehr als einen Thread** verwenden könnte (zum Beispiel in Abhängigkeiten). + +Keine Sorge, mit der Art und Weise, wie der Code strukturiert ist, werden wir sicherstellen, dass wir **eine einzige SQLModel-Session pro Anfrage** später verwenden, dies ist tatsächlich das, was `check_same_thread` zu erreichen versucht. + +### Erstellen Sie die Tabellen + +Dann fügen wir eine Funktion hinzu, die `SQLModel.metadata.create_all(engine)` verwendet, um die **Tabellen für alle Tabellenmodelle** zu erstellen. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[21:22] hl[21:22] *} + +### Erstellen Sie eine Session-Abhängigkeit + +Eine **`Session`** speichert die **Objekte im Speicher** und verfolgt alle notwendigen Änderungen in den Daten, dann **verwendet sie die `engine`**, um mit der Datenbank zu kommunizieren. + +Wir werden eine FastAPI **Abhängigkeit** mit `yield` erstellen, die eine neue `Session` für jede Anfrage bereitstellt. Dies ist das, was sicherstellt, dass wir eine einzige Session pro Anfrage verwenden. 🤓 + +Dann erstellen wir eine `Annotated` Abhängigkeit `SessionDep`, um den Rest des Codes zu vereinfachen, der diese Abhängigkeit nutzen wird. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[25:30] hl[25:27,30] *} + +### Erstellen Sie die Datenbanktabellen beim Start + +Wir werden die Datenbanktabellen erstellen, wenn die Anwendung startet. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[32:37] hl[35:37] *} + +Hier erstellen wir die Tabellen bei einem Anwendungsstart-Event. + +Für die Produktion würden Sie wahrscheinlich ein Migrationsskript verwenden, das ausgeführt wird, bevor Sie Ihre App starten. 🤓 + +/// tip | Tipp + +SQLModel wird Migrationstools mit Alembic bereitstellen, aber vorerst können Sie Alembic direkt verwenden. + +/// + +### Erstellen Sie einen Helden + +Da jedes SQLModel-Modell auch ein Pydantic-Modell ist, können Sie es in denselben **Typ-Annotationen** verwenden, die Sie für Pydantic-Modelle verwenden könnten. + +Wenn Sie beispielsweise einen Parameter vom Typ `Hero` deklarieren, wird er aus dem **JSON-Body** gelesen. + +Auf die gleiche Weise können Sie ihn als Rückgabewert der Funktion deklarieren, und dann wird die Form der Daten in der automatischen API-Dokumentations-UI angezeigt. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[40:45] hl[40:45] *} + +Hier verwenden wir die `SessionDep`-Abhängigkeit (eine `Session`), um den neuen `Hero` zum `Session`-Objekt hinzuzufügen, die Änderungen in der Datenbank zu übermitteln, die Daten im `hero` zu aktualisieren und dann zurückzugeben. + +### Helden lesen + +Wir können **Helden** aus der Datenbank mit `select()` lesen. Wir können ein `limit` und `offset` einfügen, um die Ergebnisse zu paginieren. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[48:55] hl[51:52,54] *} + +### Einen Helden lesen + +Wir können einen einzelnen **Helden** lesen. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[58:63] hl[60] *} + +### Einen Helden löschen + +Wir können auch einen **Helden** löschen. + +{* ../../docs_src/sql_databases/tutorial001_an_py310.py ln[66:73] hl[71] *} + +### Führen Sie die App aus + +Sie können die App ausführen: + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Gehen Sie dann zur `/docs` UI, Sie werden sehen, dass **FastAPI** diese **Modelle** verwendet, um die API zu **dokumentieren**, und es wird sie verwenden, um die Daten zu **serialisieren** und zu **validieren**. + +
+ +
+ +## Aktualisieren Sie die App mit mehreren Modellen + +Jetzt lassen Sie uns diese App ein wenig **umstellen**, um die **Sicherheit** und **Vielseitigkeit** zu erhöhen. + +Wenn Sie die vorherige App überprüfen, können Sie in der UI sehen, dass sie dem Client erlaubt, die `id` des zu erstellenden `Hero` zu entscheiden. 😱 + +Das sollten wir nicht zulassen, sie könnten eine `id` überschreiben, die wir bereits in der DB zugewiesen haben. Das Festlegen der `id` sollte vom **Backend** oder der **Datenbank**, **nicht vom Client** erfolgen. + +Darüber hinaus erstellen wir einen `secret_name` für den Helden, aber bisher geben wir ihn überall zurück, das ist nicht sehr **geheim**... 😅 + +Wir werden diese Dinge beheben, indem wir ein paar **zusätzliche Modelle** hinzufügen. Hier wird SQLModel glänzen. ✨ + +### Mehrere Modelle erstellen + +In **SQLModel** ist jede Modellklasse, die `table=True` hat, ein **Tabellenmodell**. + +Und jede Modellklasse, die `table=True` nicht hat, ist ein **Datenmodell**, diese sind tatsächlich nur Pydantic-Modelle (mit ein paar kleinen zusätzlichen Funktionen). 🤓 + +Mit SQLModel können wir **Vererbung** verwenden, um **doppelte Felder** in allen Fällen zu **vermeiden**. + +#### `HeroBase` - die Basisklasse + +Beginnen wir mit einem `HeroBase`-Modell, das alle **Felder, die von allen Modellen gemeinsam genutzt werden**, enthält: + +* `name` +* `age` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:9] hl[7:9] *} + +#### `Hero` - das *Tabellenmodell* + +Dann erstellen wir `Hero`, das eigentliche *Tabellenmodell*, mit den **zusätzlichen Feldern**, die nicht immer in den anderen Modellen sind: + +* `id` +* `secret_name` + +Da `Hero` von `HeroBase` erbt, hat es **auch** die **Felder**, die in `HeroBase` deklariert sind, sodass alle Felder für `Hero` sind: + +* `id` +* `name` +* `age` +* `secret_name` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:14] hl[12:14] *} + +#### `HeroPublic` - das öffentliche *Datenmodell* + +Als nächstes erstellen wir ein `HeroPublic`-Modell, dies ist das, das **an die API-Clients zurückgegeben** wird. + +Es hat dieselben Felder wie `HeroBase`, also wird es `secret_name` nicht enthalten. + +Endlich ist die Identität unserer Helden geschützt! 🥷 + +Es erklärt auch `id: int` neu. Indem wir dies tun, schließen wir einen **Vertrag** mit den API-Clients ab, sodass sie immer erwarten können, dass die `id` vorhanden ist und ein `int` ist (sie wird niemals `None` sein). + +/// tip | Tipp + +Dass das Rückgabemodell sicherstellt, dass ein Wert immer verfügbar ist und immer `int` ist (nicht `None`), ist sehr nützlich für die API-Clients, sie können viel einfacheren Code schreiben, wenn sie diese Sicherheit haben. + +Auch **automatisch generierte Clients** werden einfachere Schnittstellen haben, sodass die Entwickler, die mit Ihrer API kommunizieren, eine viel bessere Zeit haben können, mit Ihrer API zu arbeiten. 😎 + +/// + +Alle Felder in `HeroPublic` sind die gleichen wie in `HeroBase`, mit `id` als `int` (nicht `None`): + +* `id` +* `name` +* `age` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:18] hl[17:18] *} + +#### `HeroCreate` - das *Datenmodell* um einen Helden zu erstellen + +Jetzt erstellen wir ein `HeroCreate`-Modell, das die Daten von den Clients **validieren** wird. + +Es hat die gleichen Felder wie `HeroBase`, und es hat auch `secret_name`. + +Jetzt, wenn die Clients **einen neuen Helden erstellen**, senden sie den `secret_name`, er wird in der Datenbank gespeichert, aber diese geheimen Namen werden in der API nicht an die Clients zurückgegeben. + +/// tip | Tipp + +So würden Sie **Passwörter** behandeln. Sie empfangen sie, aber geben sie nicht in der API zurück. + +Sie würden auch **die Werte der Passwörter hashieren**, bevor Sie sie speichern, **niemals im Klartext speichern**. + +/// + +Die Felder von `HeroCreate` sind: + +* `name` +* `age` +* `secret_name` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:22] hl[21:22] *} + +#### `HeroUpdate` - das *Datenmodell* um einen Helden zu aktualisieren + +Wir hatten keine Möglichkeit, **einen Helden zu aktualisieren** in der vorherigen Version der App, aber jetzt mit **mehreren Modellen**, können wir es. 🎉 + +Das `HeroUpdate` *Datenmodell* ist etwas Besonderes, es hat **alle gleichen Felder**, die benötigt werden, um einen neuen Helden zu erstellen, aber alle Felder sind **optional** (sie haben alle einen Defaultwert). Auf diese Weise, wenn Sie einen Helden aktualisieren, können Sie nur die Felder senden, die Sie aktualisieren möchten. + +Da sich alle **Felder wirklich ändern** (der Typ enthält nun `None` und sie haben jetzt einen Defaultwert von `None`), müssen wir sie **neu deklarieren**. + +Wir müssen nicht wirklich von `HeroBase` erben, da wir alle Felder neu deklarieren. Ich lasse es einfach nur aus Gründen der Konsistenz erben, aber das ist nicht notwendig. Es ist mehr eine Frage des persönlichen Geschmacks. 🤷 + +Die Felder von `HeroUpdate` sind: + +* `name` +* `age` +* `secret_name` + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[7:28] hl[25:28] *} + +### Erstellen mit `HeroCreate` und Rückgabe eines `HeroPublic` + +Jetzt, da wir **mehrere Modelle** haben, können wir die Teile der App aktualisieren, die sie verwenden. + +Wir empfangen in der Anfrage ein `HeroCreate` *Datenmodell*, und daraus erstellen wir ein `Hero` *Tabellenmodell*. + +Dieses neue *Tabellenmodell* `Hero` wird die Felder haben, die vom Client gesendet wurden, und wird auch eine `id` haben, die von der Datenbank generiert wird. + +Dann geben wir das gleiche *Tabellenmodell* `Hero` wie aus der Funktion aus zurück. Aber da wir das `response_model` mit dem `HeroPublic` *Datenmodell* deklarieren, wird **FastAPI** `HeroPublic` verwenden, um die Daten zu validieren und zu serialisieren. + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[56:62] hl[56:58] *} + +/// tip | Tipp + +Jetzt verwenden wir `response_model=HeroPublic` anstelle der **Rückgabetyp-Annotation** `-> HeroPublic`, weil der Wert, den wir zurückgeben, tatsächlich *kein* `HeroPublic` ist. + +Hätten wir `-> HeroPublic` deklariert, würde Ihr Editor und Linter (berechtigterweise) meckern, dass Sie ein `Hero` statt eines `HeroPublic` zurückgeben. + +Durch die Deklaration in `response_model` sagen wir **FastAPI**, dass es sein Ding machen soll, ohne die Typ-Annotationen und die Hilfe Ihres Editors und anderer Tools zu stören. + +/// + +### Helden mit `HeroPublic` lesen + +Wir können dasselbe wie zuvor tun, um **Helden zu lesen**, erneut verwenden wir `response_model=list[HeroPublic]`, um sicherzustellen, dass die Daten korrekt validiert und serialisiert werden. + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[65:72] hl[65] *} + +### Einen Helden mit `HeroPublic` lesen + +Wir können einen einzelnen **Helden** lesen: + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[75:80] hl[77] *} + +### Update einen Helden mit `HeroUpdate` + +Wir können einen **Helden aktualisieren**. Dafür verwenden wir eine HTTP `PATCH`-Operation. + +Und im Code erhalten wir ein `dict` mit allen Daten, die vom Client gesendet wurden, **nur die Daten, die vom Client gesendet wurden**, ohne Werte, die nur für die Defaultwerte vorhanden wären. Dazu verwenden wir `exclude_unset=True`. Dies ist der Haupttrick. 🪄 + +Dann verwenden wir `hero_db.sqlmodel_update(hero_data)`, um das `hero_db` mit den Daten von `hero_data` zu aktualisieren. + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[83:93] hl[83:84,88:89] *} + +### Einen Helden erneut löschen + +Das **Löschen** eines Helden bleibt weitgehend gleich. + +Wir werden das Verlangen, alles in diesem Fall umzugestalten, nicht befriedigen. 😅 + +{* ../../docs_src/sql_databases/tutorial002_an_py310.py ln[96:103] hl[101] *} + +### Führen Sie die App erneut aus + +Sie können die App noch einmal ausführen: + +
+ +```console +$ fastapi dev main.py + +INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) +``` + +
+ +Wenn Sie zur `/docs` API UI gehen, werden Sie sehen, dass diese jetzt aktualisiert wurde. Sie wird nicht erwarten, die `id` vom Client zu erhalten, wenn sie einen Helden erstellt, usw. + +
+ +
+ +## Zusammenfassung + +Sie können **SQLModel** verwenden, um mit einer SQL-Datenbank zu interagieren und den Code mit *Datenmodellen* und *Tabellenmodellen* zu vereinfachen. + +Sie können viel mehr in den **SQLModel**-Dokumentationen lernen, es gibt ein längeres Mini Tutorial über die Verwendung von SQLModel mit **FastAPI**. 🚀