Skip to content

Commit 4867538

Browse files
authored
Merge branch 'main' into main
2 parents fe4c541 + 5dfef7e commit 4867538

14 files changed

+76
-73
lines changed

docs/release-notes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Latest Changes
44

5+
* ✏ Fix typo in `docs/tutorial/relationship-attributes/define-relationships-attributes.md`. PR [#239](https://github.com/tiangolo/sqlmodel/pull/239) by [@jalvaradosegura](https://github.com/jalvaradosegura).
6+
* ✏ Fix typo in `docs/tutorial/fastapi/simple-hero-api.md`. PR [#80](https://github.com/tiangolo/sqlmodel/pull/80) by [@joemudryk](https://github.com/joemudryk).
7+
* ✏ Fix typos in multiple files in the docs. PR [#400](https://github.com/tiangolo/sqlmodel/pull/400) by [@VictorGambarini](https://github.com/VictorGambarini).
58
* ✏ Fix typo in `docs/tutorial/code-structure.md`. PR [#344](https://github.com/tiangolo/sqlmodel/pull/344) by [@marciomazza](https://github.com/marciomazza).
69
* ✏ Fix typo in `docs/db-to-code.md`. PR [#155](https://github.com/tiangolo/sqlmodel/pull/155) by [@gr8jam](https://github.com/gr8jam).
710
* ✏ Fix typo in `docs/contributing.md`. PR [#323](https://github.com/tiangolo/sqlmodel/pull/323) by [@Fardad13](https://github.com/Fardad13).

docs/tutorial/automatic-id-none-refresh.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Automatic IDs, None Defaults, and Refreshing Data
22

3-
In the previous chapter we saw how to add rows to the database using **SQLModel**.
3+
In the previous chapter, we saw how to add rows to the database using **SQLModel**.
44

55
Now let's talk a bit about why the `id` field **can't be `NULL`** on the database because it's a **primary key**, and we declare it using `Field(primary_key=True)`.
66

@@ -11,7 +11,7 @@ But the same `id` field actually **can be `None`** in the Python code, so we dec
1111

1212
{!./docs_src/tutorial/automatic_id_none_refresh/tutorial001.py[ln:6-10]!}
1313

14-
# Code below ommitted 👇
14+
# Code below omitted 👇
1515
```
1616

1717
<details>
@@ -68,7 +68,7 @@ If we ran this code before saving the hero to the database and the `hero_1.id` w
6868
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
6969
```
7070

71-
But by declaring it with `Optional[int]` the editor will help us to avoid writing broken code by showing us a warning telling us that the code could be invalid if `hero_1.id` is `None`. 🔍
71+
But by declaring it with `Optional[int]`, the editor will help us to avoid writing broken code by showing us a warning telling us that the code could be invalid if `hero_1.id` is `None`. 🔍
7272

7373
## Print the Default `id` Values
7474

@@ -79,7 +79,7 @@ We can confirm that by printing our heroes before adding them to the database:
7979

8080
{!./docs_src/tutorial/automatic_id_none_refresh/tutorial001.py[ln:23-31]!}
8181

82-
# Code below ommitted 👇
82+
# Code below omitted 👇
8383
```
8484

8585
<details>
@@ -98,7 +98,7 @@ That will output:
9898
```console
9999
$ python app.py
100100

101-
// Output above ommitted 👆
101+
// Output above omitted 👆
102102

103103
Before interacting with the database
104104
Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
@@ -118,7 +118,7 @@ What happens when we `add` these objects to the **session**?
118118

119119
After we add the `Hero` instance objects to the **session**, the IDs are *still* `None`.
120120

121-
We can verify by creating a session using a `with` block, and adding the objects. And then printing them again:
121+
We can verify by creating a session using a `with` block and adding the objects. And then printing them again:
122122

123123
```Python hl_lines="19-21"
124124
# Code above omitted 👆
@@ -144,7 +144,7 @@ This will, again, output the `id`s of the objects as `None`:
144144
```console
145145
$ python app.py
146146

147-
// Output above ommitted 👆
147+
// Output above omitted 👆
148148

149149
After adding to the session
150150
Hero 1: id=None name='Deadpond' secret_name='Dive Wilson' age=None
@@ -165,7 +165,7 @@ Then we can `commit` the changes in the session, and print again:
165165

166166
{!./docs_src/tutorial/automatic_id_none_refresh/tutorial001.py[ln:33-48]!}
167167

168-
# Code below ommitted 👇
168+
# Code below omitted 👇
169169
```
170170

171171
<details>
@@ -184,7 +184,7 @@ And now, something unexpected happens, look at the output, it seems as if the `H
184184
```console
185185
$ python app.py
186186

187-
// Output above ommitted 👆
187+
// Output above omitted 👆
188188

189189
// Here the engine talks to the database, the SQL part
190190
INFO Engine BEGIN (implicit)

docs/tutorial/fastapi/delete.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,6 @@ After deleting it successfully, we just return a response of:
3939

4040
## Recap
4141

42-
That's it, feel free to try it out in the interactve docs UI to delete some heroes. 💥
42+
That's it, feel free to try it out in the interactive docs UI to delete some heroes. 💥
4343

4444
Using **FastAPI** to read data and combining it with **SQLModel** makes it quite straightforward to delete data from the database.

docs/tutorial/fastapi/limit-and-offset.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
When a client sends a request to get all the heroes, we have been returning them all.
44

5-
But if we had **thousands** of heroes that could consume a lot of **computational resources**, network bandwith, etc.
5+
But if we had **thousands** of heroes that could consume a lot of **computational resources**, network bandwidth, etc.
66

7-
So we probably want to limit it.
7+
So, we probably want to limit it.
88

99
Let's use the same **offset** and **limit** we learned about in the previous tutorial chapters for the API.
1010

1111
!!! info
12-
In many cases this is also called **pagination**.
12+
In many cases, this is also called **pagination**.
1313

1414
## Add a Limit and Offset to the Query Parameters
1515

@@ -38,13 +38,13 @@ And by default, we will return a maximum of `100` heroes, so `limit` will have a
3838

3939
</details>
4040

41-
We want to allow clients to set a different `offset` and `limit` values.
41+
We want to allow clients to set different `offset` and `limit` values.
4242

4343
But we don't want them to be able to set a `limit` of something like `9999`, that's over `9000`! 😱
4444

4545
So, to prevent it, we add additional validation to the `limit` query parameter, declaring that it has to be **l**ess **t**han or **e**qual to `100` with `lte=100`.
4646

47-
This way, a client can decide to take less heroes if they want, but not more.
47+
This way, a client can decide to take fewer heroes if they want, but not more.
4848

4949
!!! info
5050
If you need to refresh how query parameters and their validation work, check out the docs in FastAPI:

docs/tutorial/fastapi/multiple-models.md

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
We have been using the same `Hero` model to declare the schema of the data we receive in the API, the table model in the database, and the schema of the data we send back in responses.
44

5-
But in most of the cases there are slight differences, let's use multiple models to solve it.
5+
But in most of the cases, there are slight differences. Let's use multiple models to solve it.
66

77
Here you will see the main and biggest feature of **SQLModel**. 😎
88

99
## Review Creation Schema
1010

1111
Let's start by reviewing the automatically generated schemas from the docs UI.
1212

13-
For input we have:
13+
For input, we have:
1414

1515
<img class="shadow" alt="Interactive API docs UI" src="/img/tutorial/fastapi/simple-hero-api/image01.png">
1616

@@ -20,7 +20,7 @@ This means that the client could try to use the same ID that already exists in t
2020

2121
That's not what we want.
2222

23-
We want the client to only send the data that is needed to create a new hero:
23+
We want the client only to send the data that is needed to create a new hero:
2424

2525
* `name`
2626
* `secret_name`
@@ -63,7 +63,7 @@ The ultimate goal of an API is for some **clients to use it**.
6363

6464
The clients could be a frontend application, a command line program, a graphical user interface, a mobile application, another backend application, etc.
6565

66-
And the code those clients write depend on what our API tells them they **need to send**, and what they can **expect to receive**.
66+
And the code those clients write depends on what our API tells them they **need to send**, and what they can **expect to receive**.
6767

6868
Making both sides very clear will make it much easier to interact with the API.
6969

@@ -164,7 +164,7 @@ Let's first check how is the process to create a hero now:
164164

165165
Let's check that in detail.
166166

167-
Now we use the type annotation `HeroCreate` for the request JSON data, in the `hero` parameter of the **path operation function**.
167+
Now we use the type annotation `HeroCreate` for the request JSON data in the `hero` parameter of the **path operation function**.
168168

169169
```Python hl_lines="3"
170170
# Code above omitted 👆
@@ -180,9 +180,9 @@ The method `.from_orm()` reads data from another object with attributes and crea
180180

181181
The alternative is `Hero.parse_obj()` that reads data from a dictionary.
182182

183-
But as in this case we have a `HeroCreate` instance in the `hero` variable, this is an object with attributes, so we use `.from_orm()` to read those attributes.
183+
But as in this case, we have a `HeroCreate` instance in the `hero` variable. This is an object with attributes, so we use `.from_orm()` to read those attributes.
184184

185-
With this we 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.
185+
With this, we 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.
186186

187187
```Python hl_lines="3"
188188
# Code above omitted 👆
@@ -192,7 +192,7 @@ With this we create a new `Hero` instance (the one for the database) and put it
192192
# Code below omitted 👇
193193
```
194194

195-
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.
195+
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.
196196

197197
Because it is just refreshed, it has the `id` field set with a new ID taken from the database.
198198

@@ -206,30 +206,30 @@ And now that we return it, FastAPI will validate the data with the `response_mod
206206
# Code below omitted 👇
207207
```
208208

209-
This will validate that all the data that we promised is there, and will remove any data we didn't declare.
209+
This will validate that all the data that we promised is there and will remove any data we didn't declare.
210210

211211
!!! tip
212-
This filtering could be very important, and could be a very good security feature, for example to make sure you filter private data, hashed passwords, etc.
212+
This filtering could be very important and could be a very good security feature, for example, to make sure you filter private data, hashed passwords, etc.
213213

214214
You can read more about it in the <a href="https://fastapi.tiangolo.com/tutorial/response-model/" class="external-link" target="_blank">FastAPI docs about Response Model</a>.
215215

216-
In particular, it will make sure that the `id` is there, and that it is indeed an integer (and not `None`).
216+
In particular, it will make sure that the `id` is there and that it is indeed an integer (and not `None`).
217217

218218
## Shared Fields
219219

220220
But looking closely, we could see that these models have a lot of **duplicated information**.
221221

222-
All **the 3 models** declare that thay share some **common fields** that look exactly the same:
222+
All **the 3 models** declare that they share some **common fields** that look exactly the same:
223223

224224
* `name`, required
225225
* `secret_name`, required
226226
* `age`, optional
227227

228-
And then they declare other fields with some differences (in this case only about the `id`).
228+
And then they declare other fields with some differences (in this case, only about the `id`).
229229

230230
We want to **avoid duplicated information** if possible.
231231

232-
This is important if, for example, in the future we decide to **refactor the code** and rename one field (column). For example, from `secret_name` to `secret_identity`.
232+
This is important if, for example, in the future, we decide to **refactor the code** and rename one field (column). For example, from `secret_name` to `secret_identity`.
233233

234234
If we have that duplicated in multiple models, we could easily forget to update one of them. But if we **avoid duplication**, there's only one place that would need updating. ✨
235235

@@ -363,7 +363,7 @@ This means that there's nothing else special in this class apart from the fact t
363363

364364
As an alternative, we could use `HeroBase` directly in the API code instead of `HeroCreate`, but it would show up in the automatic docs UI with that name "`HeroBase`" which could be **confusing** for clients. Instead, "`HeroCreate`" is a bit more explicit about what it is for.
365365

366-
On top of that, we could easily decide in the future that we want to receive **more data** when creating a new hero apart from the data in `HeroBase` (for example a password), and now we already have the class to put those extra fields.
366+
On top of that, we could easily decide in the future that we want to receive **more data** when creating a new hero apart from the data in `HeroBase` (for example, a password), and now we already have the class to put those extra fields.
367367

368368
### The `HeroRead` **Data Model**
369369

@@ -390,7 +390,7 @@ This one just declares that the `id` field is required when reading a hero from
390390

391391
## Review the Updated Docs UI
392392

393-
The FastAPI code is still the same as above, we still use `Hero`, `HeroCreate`, and `HeroRead`. But now we define them in a smarter way with inheritance.
393+
The FastAPI code is still the same as above, we still use `Hero`, `HeroCreate`, and `HeroRead`. But now, we define them in a smarter way with inheritance.
394394

395395
So, we can jump to the docs UI right away and see how they look with the updated data.
396396

@@ -400,7 +400,7 @@ Let's see the new UI for creating a hero:
400400

401401
<img class="shadow" alt="Interactive API docs UI" src="/img/tutorial/fastapi/multiple-models/image02.png">
402402

403-
Nice! It now shows that to create a hero, we just pass the `name`, `secret_name`, and optinally `age`.
403+
Nice! It now shows that to create a hero, we just pass the `name`, `secret_name`, and optionally `age`.
404404

405405
We no longer pass an `id`.
406406

@@ -416,7 +416,7 @@ And if we check the schema for the **Read Heroes** *path operation* it will also
416416

417417
## Inheritance and Table Models
418418

419-
We just saw how powerful inheritance of these models can be.
419+
We just saw how powerful the inheritance of these models could be.
420420

421421
This is a very simple example, and it might look a bit... meh. 😅
422422

docs/tutorial/fastapi/read-one.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ But if the integer is not the ID of any hero in the database, it will not find a
4242

4343
So, we check it in an `if` block, if it's `None`, we raise an `HTTPException` with a `404` status code.
4444

45-
And to use it we first import `HTTPException` from `fastapi`.
45+
And to use it, we first import `HTTPException` from `fastapi`.
4646

4747
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.
4848

docs/tutorial/fastapi/relationships.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ In this case, we used `response_model=TeamRead` and `response_model=HeroRead`, s
102102

103103
Now let's stop for a second and think about it.
104104

105-
We cannot simply include *all* the data including all the internal relationships, because each **hero** has an attribute `team` with their team, and then that **team** also has an attribute `heroes` with all the **heroes** in the team, including this one.
105+
We cannot simply include *all* the data, including all the internal relationships, because each **hero** has an attribute `team` with their team, and then that **team** also has an attribute `heroes` with all the **heroes** in the team, including this one.
106106

107107
If we tried to include everything, we could make the server application **crash** trying to extract **infinite data**, going through the same hero and team over and over again internally, something like this:
108108

@@ -152,7 +152,7 @@ If we tried to include everything, we could make the server application **crash*
152152
}
153153
```
154154

155-
As you can see, in this example we would get the hero **Rusty-Man**, and from this hero we would get the team **Preventers**, and then from this team we would get its heroes, of course, including **Rusty-Man**... 😱
155+
As you can see, in this example, we would get the hero **Rusty-Man**, and from this hero we would get the team **Preventers**, and then from this team we would get its heroes, of course, including **Rusty-Man**... 😱
156156

157157
So we start again, and in the end, the server would just crash trying to get all the data with a `"Maximum recursion error"`, we would not even get a response like the one above.
158158

@@ -164,7 +164,7 @@ This is a decision that will depend on **each application**.
164164

165165
In our case, let's say that if we get a **list of heroes**, we don't want to also include each of their teams in each one.
166166

167-
And if we get a **list of teams**, we don't want to get a a list of the heroes for each one.
167+
And if we get a **list of teams**, we don't want to get a list of the heroes for each one.
168168

169169
But if we get a **single hero**, we want to include the team data (without the team's heroes).
170170

@@ -195,15 +195,15 @@ We'll add them **after** the other models so that we can easily reference the pr
195195

196196
</details>
197197

198-
These two models are very **simple in code**, but there's a lot happening here, let's check it out.
198+
These two models are very **simple in code**, but there's a lot happening here. Let's check it out.
199199

200200
### Inheritance and Type Annotations
201201

202202
The `HeroReadWithTeam` **inherits** from `HeroRead`, which means that it will have the **normal fields for reading**, including the required `id` that was declared in `HeroRead`.
203203

204204
And then it adds the **new field** `team`, which could be `None`, and is declared with the type `TeamRead` with the base fields for reading a team.
205205

206-
Then we do the same for the `TeamReadWithHeroes`, it **inherits** from `TeamRead`, and declare the **new field** `heroes` which is a list of `HeroRead`.
206+
Then we do the same for the `TeamReadWithHeroes`, it **inherits** from `TeamRead`, and declares the **new field** `heroes`, which is a list of `HeroRead`.
207207

208208
### Data Models Without Relationship Attributes
209209

@@ -213,7 +213,7 @@ Instead, here these are only **data models** that will tell FastAPI **which attr
213213

214214
### Reference to Other Models
215215

216-
Also notice that the field `team` is not declared with this new `TeamReadWithHeroes`, because that would again create that infinite recursion of data. Instead, we declare it with the normal `TeamRead` model.
216+
Also, notice that the field `team` is not declared with this new `TeamReadWithHeroes`, because that would again create that infinite recursion of data. Instead, we declare it with the normal `TeamRead` model.
217217

218218
And the same for `TeamReadWithHeroes`, the model used for the new field `heroes` uses `HeroRead` to get only each hero's data.
219219

@@ -326,12 +326,12 @@ Now we get the list of **heroes** included:
326326

327327
## Recap
328328

329-
Using the same techniques to declare additonal **data models** we can tell FastAPI what data to return in the responses, even when we return **table models**.
329+
Using the same techniques to declare additional **data models**, we can tell FastAPI what data to return in the responses, even when we return **table models**.
330330

331331
Here we almost **didn't have to change the FastAPI app** code, but of course, there will be cases where you need to get the data and process it in different ways in the *path operation function* before returning it.
332332

333333
But even in those cases, you will be able to define the **data models** to use in `response_model` to tell FastAPI how to validate and filter the data.
334334

335335
By this point, you already have a very robust API to handle data in a SQL database combining **SQLModel** with **FastAPI**, and implementing **best practices**, like data validation, conversion, filtering, and documentation. ✨
336336

337-
In the next chapter I'll tell you how to implement automated **testing** for your application using FastAPI and SQLModel. ✅
337+
In the next chapter, I'll tell you how to implement automated **testing** for your application using FastAPI and SQLModel. ✅

docs/tutorial/fastapi/response-model.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ You can see that there's a possible "Successful Response" with a code `200`, but
2222

2323
<img class="shadow" alt="API docs UI without response data schemas" src="/img/tutorial/fastapi/response-model/image01.png">
2424

25-
Right now we only tell FastAPI the data we want to receive, but we don't tell it yet the data we want to send back.
25+
Right now, we only tell FastAPI the data we want to receive, but we don't tell it yet the data we want to send back.
2626

2727
Let's do that now. 🤓
2828

0 commit comments

Comments
 (0)