Add source examples for Python 3.10 and 3.9 with updated syntax (#842)

Co-authored-by: Esteban Maya Cadavid <emayacadavid9@gmail.com>
This commit is contained in:
Sebastián Ramírez
2024-03-21 17:49:38 -05:00
committed by GitHub
parent 4c3f242ae2
commit 9141c8a920
39 changed files with 7456 additions and 25 deletions

View File

@@ -12,6 +12,32 @@ We get a `hero_id` from the path parameter and verify if it exists, just as we d
And if we actually find a hero, we just delete it with the **session**.
//// tab | Python 3.10+
```Python hl_lines="3-11"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/delete/tutorial001_py310.py[ln:89-97]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3-11"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/delete/tutorial001_py39.py[ln:91-99]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3-11"
# Code above omitted 👆
@@ -20,12 +46,34 @@ And if we actually find a hero, we just delete it with the **session**.
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/delete/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/delete/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/delete/tutorial001.py!}
```
////
///
After deleting it successfully, we just return a response of:

View File

@@ -22,6 +22,36 @@ By default, we will return the first results from the database, so `offset` will
And by default, we will return a maximum of `100` heroes, so `limit` will have a default value of `100`.
//// tab | Python 3.10+
```Python hl_lines="1 7 9"
{!./docs_src/tutorial/fastapi/limit_and_offset/tutorial001_py310.py[ln:1-2]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/limit_and_offset/tutorial001_py310.py[ln:52-56]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3 9 11"
{!./docs_src/tutorial/fastapi/limit_and_offset/tutorial001_py39.py[ln:1-4]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/limit_and_offset/tutorial001_py39.py[ln:54-58]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3 9 11"
{!./docs_src/tutorial/fastapi/limit_and_offset/tutorial001.py[ln:1-4]!}
@@ -32,12 +62,34 @@ And by default, we will return a maximum of `100` heroes, so `limit` will have a
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/limit_and_offset/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/limit_and_offset/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/limit_and_offset/tutorial001.py!}
```
////
///
We want to allow clients to set different `offset` and `limit` values.

View File

@@ -109,6 +109,36 @@ And we want to have a `HeroRead` with the `id` field, but this time annotated wi
The simplest way to solve it could be to create **multiple models**, each one with all the corresponding fields:
//// tab | Python 3.10+
```Python hl_lines="5-9 12-15 18-22"
# This would work, but there's a better option below 🚨
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py[ln:5-22]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="5-9 12-15 18-22"
# This would work, but there's a better option below 🚨
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py39.py[ln:7-24]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="5-9 12-15 18-22"
# This would work, but there's a better option below 🚨
@@ -119,12 +149,34 @@ The simplest way to solve it could be to create **multiple models**, each one wi
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001.py!}
```
////
///
Here's the important detail, and probably the most important feature of **SQLModel**: only `Hero` is declared with `table = True`.
@@ -147,6 +199,32 @@ Let's now see how to use these new models in the FastAPI application.
Let's first check how is the process to create a hero now:
//// tab | Python 3.10+
```Python hl_lines="3-4 6"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py[ln:44-51]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3-4 6"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py39.py[ln:46-53]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3-4 6"
# Code above omitted 👆
@@ -155,18 +233,66 @@ Let's first check how is the process to create a hero now:
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001.py!}
```
////
///
Let's check that in detail.
Now we use the type annotation `HeroCreate` for the request JSON data in the `hero` parameter of the **path operation function**.
//// tab | Python 3.10+
```Python hl_lines="3"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py[ln:45]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py39.py[ln:47]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3"
# Code above omitted 👆
@@ -175,6 +301,8 @@ Now we use the type annotation `HeroCreate` for the request JSON data in the `he
# Code below omitted 👇
```
////
Then we create a new `Hero` (this is the actual **table** model that saves things to the database) using `Hero.model_validate()`.
The method `.model_validate()` reads data from another object with attributes (or a dict) and creates a new instance of this class, in this case `Hero`.
@@ -187,6 +315,32 @@ In versions of **SQLModel** before `0.0.14` you would use the method `.from_orm(
We can now create a new `Hero` instance (the one for the database) and put it in the variable `db_hero` from the data in the `hero` variable that is the `HeroCreate` instance we received from the request.
//// tab | Python 3.10+
```Python hl_lines="3"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py[ln:47]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py39.py[ln:49]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3"
# Code above omitted 👆
@@ -195,12 +349,40 @@ We can now create a new `Hero` instance (the one for the database) and put it in
# Code below omitted 👇
```
////
Then we just `add` it to the **session**, `commit`, and `refresh` it, and finally, we return the same `db_hero` variable that has the just refreshed `Hero` instance.
Because it is just refreshed, it has the `id` field set with a new ID taken from the database.
And now that we return it, FastAPI will validate the data with the `response_model`, which is a `HeroRead`:
//// tab | Python 3.10+
```Python hl_lines="3"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py[ln:44]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial001_py39.py[ln:46]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3"
# Code above omitted 👆
@@ -209,6 +391,8 @@ And now that we return it, FastAPI will validate the data with the `response_mod
# Code below omitted 👇
```
////
This will validate that all the data that we promised is there and will remove any data we didn't declare.
/// tip
@@ -259,6 +443,32 @@ We can see from above that they all share some **base** fields:
So let's create a **base** model `HeroBase` that the others can inherit from:
//// tab | Python 3.10+
```Python hl_lines="3-6"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py[ln:5-8]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3-6"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py39.py[ln:7-10]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3-6"
# Code above omitted 👆
@@ -267,12 +477,34 @@ So let's create a **base** model `HeroBase` that the others can inherit from:
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002.py!}
```
////
///
As you can see, this is *not* a **table model**, it doesn't have the `table = True` config.
@@ -283,6 +515,32 @@ But now we can create the **other models inheriting from it**, they will all sha
Let's start with the only **table model**, the `Hero`:
//// tab | Python 3.10+
```Python hl_lines="9-10"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py[ln:5-12]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="9-10"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py39.py[ln:7-14]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="9-10"
# Code above omitted 👆
@@ -291,12 +549,34 @@ Let's start with the only **table model**, the `Hero`:
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002.py!}
```
////
///
Notice that `Hero` now doesn't inherit from `SQLModel`, but from `HeroBase`.
@@ -313,6 +593,32 @@ And those inherited fields will also be in the **autocompletion** and **inline e
Notice that the parent model `HeroBase` is not a **table model**, but still, we can declare `name` and `age` using `Field(index=True)`.
//// tab | Python 3.10+
```Python hl_lines="4 6 9"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py[ln:5-12]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="4 6 9"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py39.py[ln:7-14]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="4 6 9"
# Code above omitted 👆
@@ -321,12 +627,34 @@ Notice that the parent model `HeroBase` is not a **table model**, but still, we
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002.py!}
```
////
///
This won't affect this parent **data model** `HeroBase`.
@@ -339,6 +667,32 @@ Now let's see the `HeroCreate` model that will be used to define the data that w
This is a fun one:
//// tab | Python 3.10+
```Python hl_lines="13-14"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py[ln:5-16]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="13-14"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py39.py[ln:7-18]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="13-14"
# Code above omitted 👆
@@ -347,12 +701,34 @@ This is a fun one:
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002.py!}
```
////
///
What's happening here?
@@ -373,6 +749,32 @@ Now let's check the `HeroRead` model.
This one just declares that the `id` field is required when reading a hero from the API, because a hero read from the API will come from the database, and in the database it will always have an ID.
//// tab | Python 3.10+
```Python hl_lines="17-18"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py[ln:5-20]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="17-18"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py39.py[ln:7-22]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="17-18"
# Code above omitted 👆
@@ -381,12 +783,34 @@ This one just declares that the `id` field is required when reading a hero from
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/multiple_models/tutorial002.py!}
```
////
///
## Review the Updated Docs UI

View File

@@ -14,6 +14,32 @@ If you need to refresh how *path parameters* work, including their data validati
///
//// tab | Python 3.10+
```Python hl_lines="6"
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py310.py[ln:1-2]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py310.py[ln:59-65]!}
```
////
//// tab | Python 3.9+
```Python hl_lines="8"
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py39.py[ln:1-4]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py39.py[ln:61-67]!}
```
////
//// tab | Python 3.7+
```Python hl_lines="8"
{!./docs_src/tutorial/fastapi/read_one/tutorial001.py[ln:1-4]!}
@@ -22,12 +48,34 @@ If you need to refresh how *path parameters* work, including their data validati
{!./docs_src/tutorial/fastapi/read_one/tutorial001.py[ln:61-67]!}
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/read_one/tutorial001.py!}
```
////
///
For example, to get the hero with ID `2` we would send a `GET` request to:
@@ -48,6 +96,32 @@ And to use it, we first import `HTTPException` from `fastapi`.
This will let the client know that they probably made a mistake on their side and requested a hero that doesn't exist in the database.
//// tab | Python 3.10+
```Python hl_lines="1 9-11"
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py310.py[ln:1-2]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py310.py[ln:59-65]!}
```
////
//// tab | Python 3.9+
```Python hl_lines="3 11-13"
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py39.py[ln:1-4]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py39.py[ln:61-67]!}
```
////
//// tab | Python 3.7+
```Python hl_lines="3 11-13"
{!./docs_src/tutorial/fastapi/read_one/tutorial001.py[ln:1-4]!}
@@ -56,12 +130,34 @@ This will let the client know that they probably made a mistake on their side an
{!./docs_src/tutorial/fastapi/read_one/tutorial001.py[ln:61-67]!}
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/read_one/tutorial001.py!}
```
////
///
## Return the Hero
@@ -70,6 +166,32 @@ Then, if the hero exists, we return it.
And because we are using the `response_model` with `HeroRead`, it will be validated, documented, etc.
//// tab | Python 3.10+
```Python hl_lines="6 12"
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py310.py[ln:1-2]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py310.py[ln:59-65]!}
```
////
//// tab | Python 3.9+
```Python hl_lines="8 14"
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py39.py[ln:1-4]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py39.py[ln:61-67]!}
```
////
//// tab | Python 3.7+
```Python hl_lines="8 14"
{!./docs_src/tutorial/fastapi/read_one/tutorial001.py[ln:1-4]!}
@@ -78,12 +200,34 @@ And because we are using the `response_model` with `HeroRead`, it will be valida
{!./docs_src/tutorial/fastapi/read_one/tutorial001.py[ln:61-67]!}
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/read_one/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/read_one/tutorial001.py!}
```
////
///
## Check the Docs UI

View File

@@ -44,6 +44,56 @@ It's because we declared the `HeroRead` with only the same base fields of the `H
And the same way, we declared the `TeamRead` with only the same base fields of the `TeamBase` plus the `id`. But it doesn't include a field `heroes` for the **relationship attribute**.
//// tab | Python 3.10+
```Python hl_lines="3-5 9-10 14-19 23-24"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py[ln:5-7]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py[ln:20-21]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py[ln:29-34]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py[ln:43-44]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3-5 9-10 14-19 23-24"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py[ln:7-9]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py[ln:22-23]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py[ln:31-36]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py[ln:45-46]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3-5 9-10 14-19 23-24"
# Code above omitted 👆
@@ -64,18 +114,74 @@ And the same way, we declared the `TeamRead` with only the same base fields of t
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001.py!}
```
////
///
Now, remember that <a href="https://fastapi.tiangolo.com/tutorial/response-model/" class="external-link" target="_blank">FastAPI uses the `response_model` to validate and **filter** the response data</a>?
In this case, we used `response_model=TeamRead` and `response_model=HeroRead`, so FastAPI will use them to filter the response data, even if we return a **table model** that includes **relationship attributes**:
//// tab | Python 3.10+
```Python hl_lines="3 8 12 17"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py[ln:102-107]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py[ln:156-161]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3 8 12 17"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py[ln:104-109]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py[ln:158-163]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3 8 12 17"
# Code above omitted 👆
@@ -88,12 +194,34 @@ In this case, we used `response_model=TeamRead` and `response_model=HeroRead`, s
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001.py!}
```
////
///
## Don't Include All the Data
@@ -176,6 +304,32 @@ Let's add the models `HeroReadWithTeam` and `TeamReadWithHeroes`.
We'll add them **after** the other models so that we can easily reference the previous models.
//// tab | Python 3.10+
```Python hl_lines="3-4 7-8"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/relationships/tutorial001_py310.py[ln:59-64]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3-4 7-8"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/relationships/tutorial001_py39.py[ln:61-66]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3-4 7-8"
# Code above omitted 👆
@@ -184,12 +338,34 @@ We'll add them **after** the other models so that we can easily reference the pr
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/relationships/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/relationships/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/relationships/tutorial001.py!}
```
////
///
These two models are very **simple in code**, but there's a lot happening here. Let's check it out.
@@ -224,6 +400,40 @@ This will tell **FastAPI** to take the object that we return from the *path oper
In the case of the hero, this tells FastAPI to extract the `team` too. And in the case of the team, to extract the list of `heroes` too.
//// tab | Python 3.10+
```Python hl_lines="3 8 12 17"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/relationships/tutorial001_py310.py[ln:111-116]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/relationships/tutorial001_py310.py[ln:165-170]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3 8 12 17"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/relationships/tutorial001_py39.py[ln:113-118]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/relationships/tutorial001_py39.py[ln:167-172]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3 8 12 17"
# Code above omitted 👆
@@ -236,12 +446,34 @@ In the case of the hero, this tells FastAPI to extract the `team` too. And in th
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/relationships/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/relationships/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/relationships/tutorial001.py!}
```
////
///
## Check It Out in the Docs UI

View File

@@ -32,6 +32,32 @@ We can use `response_model` to tell FastAPI the schema of the data we want to se
For example, we can pass the same `Hero` **SQLModel** class (because it is also a Pydantic model):
//// tab | Python 3.10+
```Python hl_lines="3"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/response_model/tutorial001_py310.py[ln:31-37]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/response_model/tutorial001_py39.py[ln:33-39]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3"
# Code above omitted 👆
@@ -40,12 +66,34 @@ For example, we can pass the same `Hero` **SQLModel** class (because it is also
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/response_model/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/response_model/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/response_model/tutorial001.py!}
```
////
///
## List of Heroes in `response_model`
@@ -54,6 +102,34 @@ We can also use other type annotations, the same way we can use with Pydantic fi
First, we import `List` from `typing` and then we declare the `response_model` with `List[Hero]`:
//// tab | Python 3.10+
```Python hl_lines="3"
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/response_model/tutorial001_py310.py[ln:40-44]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3"
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/response_model/tutorial001_py39.py[ln:42-46]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="1 5"
{!./docs_src/tutorial/fastapi/response_model/tutorial001.py[ln:1]!}
@@ -64,12 +140,34 @@ First, we import `List` from `typing` and then we declare the `response_model` w
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/response_model/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/response_model/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/response_model/tutorial001.py!}
```
////
///
## FastAPI and Response Model

View File

@@ -6,6 +6,32 @@ Before we keep adding things, let's change a bit how we get the session for each
Up to now, we have been creating a session in each *path operation*, in a `with` block.
//// tab | Python 3.10+
```Python hl_lines="5"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/delete/tutorial001_py310.py[ln:48-55]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="5"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/delete/tutorial001_py39.py[ln:50-57]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="5"
# Code above omitted 👆
@@ -14,12 +40,34 @@ Up to now, we have been creating a session in each *path operation*, in a `with`
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/delete/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/delete/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/delete/tutorial001.py!}
```
////
///
That's perfectly fine, but in many use cases we would want to use <a href="https://fastapi.tiangolo.com/tutorial/dependencies/" class="external-link" target="_blank">FastAPI Dependencies</a>, for example to **verify** that the client is **logged in** and get the **current user** before executing any other code in the *path operation*.
@@ -34,6 +82,32 @@ A **FastAPI** dependency is very simple, it's just a function that returns a val
It could use `yield` instead of `return`, and in that case **FastAPI** will make sure it executes all the code **after** the `yield`, once it is done with the request.
//// tab | Python 3.10+
```Python hl_lines="3-5"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:40-42]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3-5"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:42-44]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3-5"
# Code above omitted 👆
@@ -42,12 +116,34 @@ It could use `yield` instead of `return`, and in that case **FastAPI** will make
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py!}
```
////
///
## Use the Dependency
@@ -56,6 +152,44 @@ Now let's make FastAPI execute a dependency and get its value in the *path opera
We import `Depends()` from `fastapi`. Then we use it in the *path operation function* in a **parameter**, the same way we declared parameters to get JSON bodies, path parameters, etc.
//// tab | Python 3.10+
```Python hl_lines="1 13"
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:1-2]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:40-42]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:53-59]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3 15"
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:1-4]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:42-44]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:55-61]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3 15"
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:1-4]!}
@@ -70,12 +204,34 @@ We import `Depends()` from `fastapi`. Then we use it in the *path operation func
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py!}
```
////
///
/// tip
@@ -104,6 +260,44 @@ And because dependencies can use `yield`, FastAPI will make sure to run the code
This means that in the main code of the *path operation function*, it will work equivalently to the previous version with the explicit `with` block.
//// tab | Python 3.10+
```Python hl_lines="14-18"
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:1-2]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:40-42]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:53-59]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="16-20"
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:1-4]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:42-44]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:55-61]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="16-20"
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:1-4]!}
@@ -118,18 +312,78 @@ This means that in the main code of the *path operation function*, it will work
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py!}
```
////
///
In fact, you could think that all that block of code inside of the `create_hero()` function is still inside a `with` block for the **session**, because this is more or less what's happening behind the scenes.
But now, the `with` block is not explicitly in the function, but in the dependency above:
//// tab | Python 3.10+
```Python hl_lines="7-8"
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:1-2]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:40-42]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:53-59]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="9-10"
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:1-4]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:42-44]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:55-61]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="9-10"
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:1-4]!}
@@ -144,12 +398,34 @@ But now, the `with` block is not explicitly in the function, but in the dependen
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py!}
```
////
///
We will see how this is very useful when testing the code later. ✅
@@ -166,6 +442,40 @@ session: Session = Depends(get_session)
And then we remove the previous `with` block with the old **session**.
//// tab | Python 3.10+
```Python hl_lines="13 24 33 42 57"
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:1-2]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:40-42]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py[ln:53-104]!}
```
////
//// tab | Python 3.9+
```Python hl_lines="15 26 35 44 59"
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:1-4]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:42-44]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py[ln:55-106]!}
```
////
//// tab | Python 3.7+
```Python hl_lines="15 26 35 44 59"
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:1-4]!}
@@ -178,12 +488,34 @@ And then we remove the previous `with` block with the old **session**.
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py[ln:55-106]!}
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/session_with_dependency/tutorial001.py!}
```
////
///
## Recap

View File

@@ -32,6 +32,22 @@ We will start with the **simplest version**, with just heroes (no teams yet).
This is almost the same code we have seen up to now in previous examples:
//// tab | Python 3.10+
```Python hl_lines="18-19"
# One line of FastAPI imports here later 👈
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py[ln:2]!}
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py[ln:5-20]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="20-21"
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001.py[ln:1]!}
@@ -43,12 +59,26 @@ This is almost the same code we have seen up to now in previous examples:
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001.py!}
```
////
///
There's only one change here from the code we have used before, the `check_same_thread` in the `connect_args`.
@@ -77,6 +107,22 @@ We will import the `FastAPI` class from `fastapi`.
And then create an `app` object that is an instance of that `FastAPI` class:
//// tab | Python 3.10+
```Python hl_lines="1 6"
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py[ln:1-2]!}
# SQLModel code here omitted 👈
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py[ln:23]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3 8"
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001.py[ln:1-4]!}
@@ -87,12 +133,26 @@ And then create an `app` object that is an instance of that `FastAPI` class:
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001.py!}
```
////
///
## Create Database and Tables on `startup`
@@ -101,6 +161,20 @@ We want to make sure that once the app starts running, the function `create_tabl
This should be called only once at startup, not before every request, so we put it in the function to handle the `"startup"` event:
//// tab | Python 3.10+
```Python hl_lines="6-8"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py[ln:23-28]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="6-8"
# Code above omitted 👆
@@ -109,12 +183,26 @@ This should be called only once at startup, not before every request, so we put
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001.py!}
```
////
///
## Create Heroes *Path Operation*
@@ -129,6 +217,20 @@ Let's create the **path operation** code to create a new hero.
It will be called when a user sends a request with a `POST` **operation** to the `/heroes/` **path**:
//// tab | Python 3.10+
```Python hl_lines="11-12"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py[ln:23-37]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="11-12"
# Code above omitted 👆
@@ -137,12 +239,26 @@ It will be called when a user sends a request with a `POST` **operation** to the
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001.py!}
```
////
///
/// info
@@ -177,18 +293,44 @@ We will improve this further later, but for now, it already shows the power of h
Now let's add another **path operation** to read all the heroes:
//// tab | Python 3.10+
```Python hl_lines="20-24"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py[ln:23-44]!}
```
////
//// tab | Python 3.7+
```Python hl_lines="20-24"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001.py[ln:25-46]!}
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001_py310.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/simple_hero_api/tutorial001.py!}
```
////
///
This is pretty straightforward.

View File

@@ -18,18 +18,62 @@ Then we also inherit from the `TeamBase` for the `TeamCreate` and `TeamRead` **d
And we also create a `TeamUpdate` **data model**.
//// tab | Python 3.10+
```Python hl_lines="5-7 10-13 16-17 20-21 24-26"
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py[ln:1-26]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="7-9 12-15 18-19 22-23 26-28"
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py[ln:1-28]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="7-9 12-15 18-19 22-23 26-28"
{!./docs_src/tutorial/fastapi/teams/tutorial001.py[ln:1-28]!}
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001.py!}
```
////
///
We now also have **relationship attributes**. 🎉
@@ -38,7 +82,33 @@ Let's now update the `Hero` models too.
## Update Hero Models
```Python hl_lines="3-8 11-15 17-18 21-22 25-29"
//// tab | Python 3.10+
```Python hl_lines="3-8 11-14 17-18 21-22 25-29"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py[ln:29-55]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3-8 11-14 17-18 21-22 25-29"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py[ln:31-57]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3-8 11-14 17-18 21-22 25-29"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/teams/tutorial001.py[ln:31-57]!}
@@ -46,12 +116,34 @@ Let's now update the `Hero` models too.
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001.py!}
```
////
///
We now have a `team_id` in the hero models.
@@ -64,6 +156,32 @@ And even though the `HeroBase` is *not* a **table model**, we can declare `team_
Notice that the **relationship attributes**, the ones with `Relationship()`, are **only** in the **table models**, as those are the ones that are handled by **SQLModel** with SQLAlchemy and that can have the automatic fetching of data from the database when we access them.
//// tab | Python 3.10+
```Python hl_lines="11 38"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py[ln:5-55]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="11 38"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py[ln:7-57]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="11 38"
# Code above omitted 👆
@@ -72,12 +190,34 @@ Notice that the **relationship attributes**, the ones with `Relationship()`, are
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001.py!}
```
////
///
## Path Operations for Teams
@@ -86,6 +226,32 @@ Let's now add the **path operations** for teams.
These are equivalent and very similar to the **path operations** for the **heroes** we had before, so we don't have to go over the details for each one, let's check the code.
//// tab | Python 3.10+
```Python hl_lines="3-9 12-20 23-28 31-47 50-57"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py[ln:136-190]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3-9 12-20 23-28 31-47 50-57"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py[ln:138-192]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3-9 12-20 23-28 31-47 50-57"
# Code above omitted 👆
@@ -94,12 +260,34 @@ These are equivalent and very similar to the **path operations** for the **heroe
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/teams/tutorial001.py!}
```
////
///
## Using Relationships Attributes

View File

@@ -38,6 +38,32 @@ The `Hero` table model will now store a new field `hashed_password`.
And the data models for `HeroCreate` and `HeroUpdate` will also have a new field `password` that will contain the plain text password sent by clients.
//// tab | Python 3.10+
```Python hl_lines="11 15 26"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial002_py310.py[ln:5-28]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="11 15 26"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial002_py39.py[ln:7-30]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="11 15 26"
# Code above omitted 👆
@@ -46,12 +72,34 @@ And the data models for `HeroCreate` and `HeroUpdate` will also have a new field
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002.py!}
```
////
///
When a client is creating a new hero, they will send the `password` in the request body.
@@ -64,6 +112,40 @@ The app will receive the data from the client using the `HeroCreate` model.
This contains the `password` field with the plain text password, and we cannot use that one. So we need to generate a hash from it.
//// tab | Python 3.10+
```Python hl_lines="11"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial002_py310.py[ln:42-44]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/update/tutorial002_py310.py[ln:55-57]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="11"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial002_py39.py[ln:44-46]!}
# Code here omitted 👈
{!./docs_src/tutorial/fastapi/update/tutorial002_py39.py[ln:57-59]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="11"
# Code above omitted 👆
@@ -76,12 +158,34 @@ This contains the `password` field with the plain text password, and we cannot u
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002.py!}
```
////
///
## Create an Object with Extra Data
@@ -138,6 +242,32 @@ So now, `db_user_dict` has the updated `age` field with `32` instead of `None` a
Similar to how dictionaries have an `update` method, **SQLModel** models have a parameter `update` in `Hero.model_validate()` that takes a dictionary with extra data, or data that should take precedence:
//// tab | Python 3.10+
```Python hl_lines="8"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial002_py310.py[ln:55-64]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="8"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial002_py39.py[ln:57-66]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="8"
# Code above omitted 👆
@@ -146,12 +276,34 @@ Similar to how dictionaries have an `update` method, **SQLModel** models have a
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002.py!}
```
////
///
Now, `db_hero` (which is a *table model* `Hero`) will extract its values from `hero` (which is a *data model* `HeroCreate`), and then it will **`update`** its values with the extra data from the dictionary `extra_data`.
@@ -166,6 +318,32 @@ Now let's say we want to **update a hero** that already exists in the database.
The same way as before, to avoid removing existing data, we will use `exclude_unset=True` when calling `hero.model_dump()`, to get a dictionary with only the data sent by the client.
//// tab | Python 3.10+
```Python hl_lines="9"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial002_py310.py[ln:83-89]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="9"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial002_py39.py[ln:85-91]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="9"
# Code above omitted 👆
@@ -174,12 +352,34 @@ The same way as before, to avoid removing existing data, we will use `exclude_un
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002.py!}
```
////
///
Now, this `hero_data` dictionary could contain a `password`. We need to check it, and if it's there, we need to generate the `hashed_password`.
@@ -190,6 +390,32 @@ And then we can update the `db_hero` object using the method `db_hero.sqlmodel_u
It takes a model object or dictionary with the data to update the object and also an **additional `update` argument** with extra data.
//// tab | Python 3.10+
```Python hl_lines="15"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial002_py310.py[ln:83-99]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="15"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial002_py39.py[ln:85-101]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="15"
# Code above omitted 👆
@@ -198,12 +424,34 @@ It takes a model object or dictionary with the data to update the object and als
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial002.py!}
```
////
///
/// tip

View File

@@ -22,6 +22,32 @@ Because each field is **actually different** (we just change it to `Optional`, b
So, let's create this new `HeroUpdate` model:
//// tab | Python 3.10+
```Python hl_lines="21-24"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial001_py310.py[ln:5-26]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="21-24"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial001_py39.py[ln:7-28]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="21-24"
# Code above omitted 👆
@@ -30,12 +56,34 @@ So, let's create this new `HeroUpdate` model:
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001.py!}
```
////
///
This is almost the same as `HeroBase`, but all the fields are optional, so we can't simply inherit from `HeroBase`.
@@ -46,6 +94,32 @@ Now let's use this model in the *path operation* to update a hero.
We will use a `PATCH` HTTP operation. This is used to **partially update data**, which is what we are doing.
//// tab | Python 3.10+
```Python hl_lines="3-4"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial001_py310.py[ln:74-89]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="3-4"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial001_py39.py[ln:76-91]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="3-4"
# Code above omitted 👆
@@ -54,12 +128,34 @@ We will use a `PATCH` HTTP operation. This is used to **partially update data**,
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001.py!}
```
////
///
We also read the `hero_id` from the *path parameter* and the request body, a `HeroUpdate`.
@@ -70,6 +166,32 @@ We take a `hero_id` with the **ID** of the hero **we want to update**.
So, we need to read the hero from the database, with the **same logic** we used to **read a single hero**, checking if it exists, possibly raising an error for the client if it doesn't exist, etc.
//// tab | Python 3.10+
```Python hl_lines="6-8"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial001_py310.py[ln:74-89]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="6-8"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial001_py39.py[ln:76-91]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="6-8"
# Code above omitted 👆
@@ -78,12 +200,34 @@ So, we need to read the hero from the database, with the **same logic** we used
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001.py!}
```
////
///
### Get the New Data
@@ -136,6 +280,32 @@ Then the dictionary we would get in Python using `hero.model_dump(exclude_unset=
Then we use that to get the data that was actually sent by the client:
//// tab | Python 3.10+
```Python hl_lines="9"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial001_py310.py[ln:74-89]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="9"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial001_py39.py[ln:76-91]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="9"
# Code above omitted 👆
@@ -144,12 +314,34 @@ Then we use that to get the data that was actually sent by the client:
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001.py!}
```
////
///
/// tip
@@ -160,6 +352,32 @@ Before SQLModel 0.0.14, the method was called `hero.dict(exclude_unset=True)`, b
Now that we have a **dictionary with the data sent by the client**, we can use the method `db_hero.sqlmodel_update()` to update the object `db_hero`.
//// tab | Python 3.10+
```Python hl_lines="10"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial001_py310.py[ln:74-89]!}
# Code below omitted 👇
```
////
//// tab | Python 3.9+
```Python hl_lines="10"
# Code above omitted 👆
{!./docs_src/tutorial/fastapi/update/tutorial001_py39.py[ln:76-91]!}
# Code below omitted 👇
```
////
//// tab | Python 3.7+
```Python hl_lines="10"
# Code above omitted 👆
@@ -168,12 +386,34 @@ Now that we have a **dictionary with the data sent by the client**, we can use t
# Code below omitted 👇
```
////
/// details | 👀 Full file preview
//// tab | Python 3.10+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001_py310.py!}
```
////
//// tab | Python 3.9+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001_py39.py!}
```
////
//// tab | Python 3.7+
```Python
{!./docs_src/tutorial/fastapi/update/tutorial001.py!}
```
////
///
/// tip