Skip to content
2 changes: 1 addition & 1 deletion docs/advanced/decimal.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Total money: 3.300

/// warning

Although Decimal types are supported and used in the Python side, not all databases support it. In particular, SQLite doesn't support decimals, so it will convert them to the same floating `NUMERIC` type it supports.
Although Decimal types are supported and used on the Python side, not all databases support them. In particular, SQLite doesn't support decimals, so it will convert them to the same floating `NUMERIC` type it supports.

But decimals are supported by most of the other SQL databases. 🎉

Expand Down
2 changes: 1 addition & 1 deletion docs/advanced/uuid.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ There are several versions of UUID, some versions include the current time in th

### Distributed UUIDs

You could generate one UUID in one computer, and someone else could generate another UUID in another computer, and it would be almost **impossible** for both UUIDs to be the **same**.
You could generate one UUID on one computer, and someone else could generate another UUID on another computer, and it would be almost **impossible** for both UUIDs to be the **same**.

This means that you don't have to wait for the DB to generate the ID for you, you can **generate it in code before sending it to the database**, because you can be quite certain it will be unique.

Expand Down
10 changes: 5 additions & 5 deletions docs/databases.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ In most of the cases, the objective of your program is to do something with data

* It could be just moving **files** from one place to the other.
* Or it could be taking data from the user in the **terminal** and showing it differently.
* Or a **web API** that takes some data and process it in some way, etc.
* Or a **web API** that takes some data and processes it in some way, etc.

In most cases, the data *comes from outside* the program or *ends outside the program* (for example, shown on the screen, in a file, etc).

Expand Down Expand Up @@ -108,9 +108,9 @@ Having distributed systems also creates additional challenges, so there's a high

We already talked about the different ways to interact with a database and how they handle files, etc. That applies to most or all of the databases.

But there's another way to categorize databases that is very important. As you can imagine, there are many types of databases and many databases in each group. But in general, they can be separated in two big groups: "SQL Databases" and "NoSQL Databases".
But there's another way to categorize databases that is very important. As you can imagine, there are many types of databases and many databases in each group. But in general, they can be separated into two big groups: "SQL Databases" and "NoSQL Databases".

We will get to why the name "SQL" in a bit, but first, let's see what is it all about.
We will get to why the name "SQL" in a bit, but first, let's see what it is all about.

### SQLModel for SQL Databases

Expand All @@ -137,7 +137,7 @@ If we worked with a single table to store our heroes, it could be like this:
<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team</th><th>headquarters</th>
</tr>
<tr>
<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>Z-Factor</td><td>Sister Margaret's Bar</td>
<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>Z-Force</td><td>Sister Margaret's Bar</td>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's Z-Force everywhere else, and I checked it's not intentional

</tr>
<tr>
<td>2</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>Preventers</td><td>Sharp Tower</td>
Expand Down Expand Up @@ -279,7 +279,7 @@ And because of this technical term, these **SQL Databases** are also called **Re

After developing these ideas of how to store data in multiple tables they also created a **language** that could be used to interact with them.

The language is called **SQL**, the name comes from for **Structured Query Language**.
The language is called **SQL**, the name comes from **Structured Query Language**.

Nevertheless, the language is not only used to *query* for data. It is also used to create records/rows, to update them, to delete them. And to manipulate the database, create tables, etc.

Expand Down
4 changes: 2 additions & 2 deletions docs/db-to-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ The process of making sure that whatever the external user sends is safe to use

It comes by default in **SQLModel** (thanks to SQLAlchemy). And many other similar tools would also provide that functionality among many other features.

Now you are ready for [a joke from xkcd](https://xkcd.com/327/):
Now you are ready for [a joke from xkcd](https://xkcd.com/327/):

![Exploits of a Mom](https://imgs.xkcd.com/comics/exploits_of_a_mom.png)

Expand Down Expand Up @@ -244,7 +244,7 @@ These types of libraries like **SQLModel** (and of course, SQLAlchemy) that tran

**ORM** means **Object-Relational Mapper**.

This is a very common term, but it also comes from quite technical and **academical** concepts 👩‍🎓:
This is a very common term, but it also comes from quite technical and **academic** concepts 👩‍🎓:

* **Object**: refers to code with classes and instances, normally called "Object Oriented Programming", that's why the "**Object**" part.

Expand Down
6 changes: 3 additions & 3 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Nevertheless, SQLModel is completely **independent** of FastAPI and can be used

It's all based on standard <abbr title="Currently supported versions of Python">modern **Python**</abbr> type annotations. No new syntax to learn. Just standard modern Python.

If you need a 2 minute refresher of how to use Python types (even if you don't use SQLModel or FastAPI), check the FastAPI tutorial section: [Python types intro](https://fastapi.tiangolo.com/python-types/).
If you need a 2 minute refresher on how to use Python types (even if you don't use SQLModel or FastAPI), check the FastAPI tutorial section: [Python types intro](https://fastapi.tiangolo.com/python-types/).

You will also see a 20 seconds refresher on the section [Tutorial - User Guide: First Steps](tutorial/index.md).

Expand Down Expand Up @@ -56,7 +56,7 @@ And later, you can fine-tune everything with all the power of SQLAlchemy and Pyd

Underneath, ✨ a **SQLModel** model is also a **Pydantic** model. ✨

There was a lot of research and effort dedicated to make it that way.
There was a lot of research and effort dedicated to making it that way.

That means you get all of **Pydantic's features**, including automatic data **validation**, **serialization**, and **documentation**. You can use SQLModel in the same way you can use Pydantic.

Expand All @@ -74,7 +74,7 @@ You will learn more about combining different models later in the tutorial.

Underneath, ✨ a **SQLModel** model is also a **SQLAlchemy** model. ✨

There was **a lot** of research and effort dedicated to make it that way. In particular, there was a lot of effort and experimentation in making a single model be **both a SQLAlchemy model and a Pydantic** model at the same time.
There was **a lot** of research and effort dedicated to making it that way. In particular, there was a lot of effort and experimentation in making a single model be **both a SQLAlchemy model and a Pydantic** model at the same time.

That means that you get all the power, robustness, and certainty of SQLAlchemy, the [most widely used database library in Python](https://lp.jetbrains.com/python-developers-survey-2024/#orms).

Expand Down
2 changes: 1 addition & 1 deletion docs/help.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ You can follow **FastAPI** online in several places:

You can "star" SQLModel in GitHub (clicking the star button at the top right): [https://github.com/fastapi/sqlmodel](https://github.com/fastapi/sqlmodel). ⭐️

By adding a star, other users will be able to find it more easily and see that it has been already useful for others.
By adding a star, other users will be able to find it more easily and see that it has already been useful for others.

## Watch the GitHub repository for releases

Expand Down
2 changes: 1 addition & 1 deletion docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,4 @@ Go ahead and [Install DB Browser for SQLite](https://sqlitebrowser.org/), it's f

## Next Steps

Okay, let's get going! On the next section we'll start the [Tutorial - User Guide](tutorial/index.md). 🚀
Okay, let's get going! In the next section we'll start the [Tutorial - User Guide](tutorial/index.md). 🚀
6 changes: 3 additions & 3 deletions docs/tutorial/automatic-id-none-refresh.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ When we create a new `Hero` instance, we don't set the `id`:

### How `int | None` Helps

Because we don't set the `id`, it takes the Python's default value of `None` that we set in `Field(default=None)`.
Because we don't set the `id`, it takes Python's default value of `None` that we set in `Field(default=None)`.

This is the only reason why we define it with `int | None` and with a default value of `None`.

Expand Down Expand Up @@ -249,7 +249,7 @@ session.refresh(hero_1)

...the **session** goes and makes the **engine** communicate with the database to get the recent data for this object `hero_1`, and then the **session** puts the data in the `hero_1` object and marks it as "fresh" or "not expired".

Here's how the output would look like:
Here's what the output would look like:

<div class="termy">

Expand Down Expand Up @@ -442,4 +442,4 @@ If you understood all that, now you know a lot about **SQLModel**, SQLAlchemy, a

If you didn't get all that, it's fine, you can always come back later to <abbr title="See what I did there? 😜">`refresh`</abbr> the concepts.

I think this might be one of the main types of bugs that cause problems and makes you scratch your head. So, good job studying it! 💪
I think this might be one of the main types of bugs that cause problems and make you scratch your head. So, good job studying it! 💪

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make refers to bugs here

6 changes: 3 additions & 3 deletions docs/tutorial/code-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ from .models import Hero, Team
from .database import engine
```

We can use these relative imports because, for example, in the file `app.py` (the `app` module) Python knows that it is **part of our Python package** because it is in the same directory as the file `__init__.py`. And all the Python files on the same directory are part of the same Python package too.
We can use these relative imports because, for example, in the file `app.py` (the `app` module) Python knows that it is **part of our Python package** because it is in the same directory as the file `__init__.py`. And all the Python files in the same directory are part of the same Python package too.

### Models File

Expand Down Expand Up @@ -203,7 +203,7 @@ Using that trick of `TYPE_CHECKING` we can "import" the `Team` in `hero_model.py

{* ./docs_src/tutorial/code_structure/tutorial002_py310/hero_model.py hl[1,5:6,16] *}

Have in mind that now we *have* to put the annotation of `Team` as a string: `"Team"`, so that Python doesn't have errors at runtime.
Keep in mind that now we *have* to put the annotation of `Team` as a string: `"Team"`, so that Python doesn't have errors at runtime.

### Team Model File

Expand All @@ -221,7 +221,7 @@ Now, just for completeness, the `app.py` file would import the models from both

And of course, all the tricks with `TYPE_CHECKING` and type annotations in strings are **only needed in the files with circular imports**.

As there are no circular imports with `app.py`, we can just use normal imports and use the classes as normally here.
As there are no circular imports with `app.py`, we can just use normal imports and use the classes normally here.

And running that achieves the same result as before:

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorial/connect/create-connected-tables.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ CREATE TABLE hero (
)
```

The only new is the `FOREIGN KEY` line, and as you can see, it tells the database what column in this table is a foreign key (`team_id`), which other (foreign) table it references (`team`) and which column in that table is the key to define which row to connect (`id`).
The only new part is the `FOREIGN KEY` line, and as you can see, it tells the database what column in this table is a foreign key (`team_id`), which other (foreign) table it references (`team`) and which column in that table is the key to define which row to connect (`id`).

Feel free to experiment with it in **DB Browser for SQLite**.

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorial/connect/read-connected-data.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ This `JOIN` will be useful in a bit to be able to also get Spider-Boy, even if h

The same way there's a `.where()` available when using `select()`, there's also a `.join()`.

And in SQLModel (actually SQLAlchemy), when using the `.join()`, because we already declared what is the `foreign_key` when creating the models, we don't have to pass an `ON` part, it is inferred automatically:
And in SQLModel (actually SQLAlchemy), we don't have to pass an `ON` part when using `.join()`. It is inferred automatically because we already declared the `foreign_key` in the model definition:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a wrong word order in initial sentence:

we already declared what is the foreign_key

should be

we already declared what the foreign_key is

(is should go after the subject)

But just moving "is" to correct place made the whole sentence even harder to read. I suggest rephrasing it this way


{* ./docs_src/tutorial/connect/select/tutorial002_py310.py ln[61:66] hl[63] *}

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorial/connect/update-data-connections.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ And a `hero` table:

Some of these heroes are part of a team.

Now we'll see how to **update** those connections between rows tables.
Now we'll see how to **update** those connections between rows in tables.

We will continue with the code we used to create some heroes, and we'll update them.

Expand Down
8 changes: 4 additions & 4 deletions docs/tutorial/create-db-and-table-with-db-browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ You will see again the same table we created.

## Create the Table again, with SQL

Now, to see how is it that SQL works, let's create the table again, but with SQL.
Now, to see how SQL works, let's create the table again, but with SQL.

Click the <kbd>Close Database</kbd> button again.

Expand Down Expand Up @@ -151,7 +151,7 @@ You will see the "execution finished successfully" message.

<img class="shadow" src="/img/create-db-and-table-with-db-browser/image010.png">

And if you go back to the <kbd>Database Structure</kbd> tab, you will see that you effectively created again the same table.
And if you go back to the <kbd>Database Structure</kbd> tab, you will see that you effectively created the same table again.

<img class="shadow" src="/img/create-db-and-table-with-db-browser/image008.png">

Expand All @@ -163,12 +163,12 @@ But if you are curious and want to get a quick overview of SQL, I recommend the

You can start with [`CREATE TABLE`](https://www.sqlite.org/lang_createtable.html).

Of course, you can also go and take a full SQL course or read a book about SQL, but you don't need more than what I'll explain here on the tutorial to start being productive with **SQLModel**. 🤓
Of course, you can also go and take a full SQL course or read a book about SQL, but you don't need more than what I'll explain here in the tutorial to start being productive with **SQLModel**. 🤓

## Recap

We saw how to interact with SQLite databases in files using **DB Browser for SQLite** in a visual user interface.

We also saw how to use it to write some SQL directly to the SQLite database. This will be useful to verify the data in the database is looking correctly, to debug, etc.
We also saw how to use it to write some SQL directly to the SQLite database. This will be useful to verify the data in the database looks correct, to debug, etc.

In the next chapters we will start using **SQLModel** to interact with the database, and we will continue to use **DB Browser for SQLite** at the same time to look at the database underneath. 🔍
8 changes: 4 additions & 4 deletions docs/tutorial/create-db-and-table.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ And the type of each of them will also be the type of table column:

{* ./docs_src/tutorial/create_db_and_table/tutorial001_py310.py ln[1:8] hl[1,5:8] *}

Let's now see with more detail these field/column declarations.
Let's now see these field/column declarations in more detail.

### `None` Fields, Nullable Columns

Expand Down Expand Up @@ -152,7 +152,7 @@ Creating the **engine** is very simple, just call `create_engine()` with a URL f

{* ./docs_src/tutorial/create_db_and_table/tutorial001_py310.py ln[1:16] hl[1,14] *}

You should normally have a single **engine** object for your whole application and re-use it everywhere.
You should normally have a single **engine** object for your whole application and reuse it everywhere.

/// tip

Expand Down Expand Up @@ -402,7 +402,7 @@ The same way, there are several possible types for storing strings. SQLite uses

SQLAlchemy generates the SQL statements to create tables using `VARCHAR`, and then SQLite receives them, and internally converts them to `TEXT`s.

Additional to the difference between those two data types, some databases like MySQL require setting a maximum length for the `VARCHAR` types, for example `VARCHAR(255)` sets the maximum number of characters to 255.
In addition to the difference between those two data types, some databases like MySQL require setting a maximum length for the `VARCHAR` types, for example `VARCHAR(255)` sets the maximum number of characters to 255.

To make it easier to start using **SQLModel** right away independent of the database you use (even with MySQL), and without any extra configurations, by default, `str` fields are interpreted as `VARCHAR` in most databases and `VARCHAR(255)` in MySQL, this way you know the same class will be compatible with the most popular databases without extra effort.

Expand Down Expand Up @@ -570,7 +570,7 @@ Review what each line does by clicking each number bubble in the code. 👆

## Recap

We learnt how to use **SQLModel** to define how a table in the database should look like, and we created a database and a table using **SQLModel**.
We learnt how to use **SQLModel** to define what a table in the database should look like, and we created a database and a table using **SQLModel**.

We also refactored the code to make it easier to reuse, share, and test later.

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorial/delete.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ You can try that in **DB Browser for SQLite**:

<img class="shadow" src="/img/tutorial/delete/image01.png">

Have in mind that `DELETE` is to delete entire **rows**, not single values in a row.
Keep in mind that `DELETE` is to delete entire **rows**, not single values in a row.

If you want to "delete" a single value in a column while **keeping the row**, you would instead **update** the row as explained in the previous chapter, setting the specific value of the column in that row to `NULL` (to `None` in Python).

Expand Down
6 changes: 3 additions & 3 deletions docs/tutorial/fastapi/multiple-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ But we also want to have a `HeroCreate` for the data we want to receive when **c
* `secret_name`, required
* `age`, optional

And we want to have a `HeroPublic` with the `id` field, but this time with a type of `id: int`, instead of `id: int | None`, to make it clear that it will always have an `int` in responses **read** from the clients:
And we want to have a `HeroPublic` with the `id` field, but this time with a type of `id: int`, instead of `id: int | None`, to make it clear that it will always have an `int` in responses **read** by the clients:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Responses are being read by clients, not from clients


* `id`, required
* `name`, required
Expand Down Expand Up @@ -129,7 +129,7 @@ We will improve this code to avoid duplicating the fields, but for now we can co

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:
Let's first check how we create a hero now:

{* ./docs_src/tutorial/fastapi/multiple_models/tutorial001_py310.py ln[44:51] hl[44:45,47] *}

Expand Down Expand Up @@ -235,7 +235,7 @@ And those inherited fields will also be in the **autocompletion** and **inline e

### Columns and Inheritance with Multiple Models

Notice that the parent model `HeroBase` is not a **table model**, but still, we can declare `name` and `age` using `Field(index=True)`.
Notice that the parent model `HeroBase` is not a **table model**, but still, we can declare `name` and `age` using `Field(index=True)`.

{* ./docs_src/tutorial/fastapi/multiple_models/tutorial002_py310.py ln[5:12] hl[6,8,11] *}

Expand Down
2 changes: 1 addition & 1 deletion docs/tutorial/fastapi/read-one.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ For example, to get the hero with ID `2` we would send a `GET` request to:

## Handling Errors

Then, because FastAPI already takes care of making sure that the `hero_id` is an actual integer, we can use it directly with `Hero.get()` to try and get one hero by that ID.
Then, because FastAPI already takes care of making sure that the `hero_id` is an actual integer, we can use it directly with `session.get()` to try and get one hero by that ID.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no such syntax in SQLModel. In code example it's hero = session.get(Hero, hero_id)


But if the integer is not the ID of any hero in the database, it will not find anything, and the variable `hero` will be `None`.

Expand Down
Loading