diff --git a/docs/advanced/decimal.md b/docs/advanced/decimal.md
index c0541b7..3cd9163 100644
--- a/docs/advanced/decimal.md
+++ b/docs/advanced/decimal.md
@@ -21,15 +21,21 @@ In most cases this would probably not be a problem, for example measuring views
Pydantic has special support for `Decimal` types using the `condecimal()` special function.
-!!! tip
- Pydantic 1.9, that will be released soon, has improved support for `Decimal` types, without needing to use the `condecimal()` function.
+/// tip
- But meanwhile, you can already use this feature with `condecimal()` in **SQLModel** it as it's explained here.
+Pydantic 1.9, that will be released soon, has improved support for `Decimal` types, without needing to use the `condecimal()` function.
+
+But meanwhile, you can already use this feature with `condecimal()` in **SQLModel** it as it's explained here.
+
+///
When you use `condecimal()` you can specify the number of digits and decimal places to support. They will be validated by Pydantic (for example when using FastAPI) and the same information will also be used for the database columns.
-!!! info
- For the database, **SQLModel** will use SQLAlchemy's `DECIMAL` type.
+/// info
+
+For the database, **SQLModel** will use SQLAlchemy's `DECIMAL` type.
+
+///
## Decimals in SQLModel
@@ -72,8 +78,11 @@ We are also saying that the number of decimal places (to the right of the decima
* `123`
* Even though this number doesn't have any decimals, we still have 3 places saved for them, which means that we can **only use 2 places** for the **integer part**, and this number has 3 integer digits. So, the allowed number of integer digits is `max_digits` - `decimal_places` = 2.
-!!! tip
- Make sure you adjust the number of digits and decimal places for your own needs, in your own application. 🤓
+/// tip
+
+Make sure you adjust the number of digits and decimal places for your own needs, in your own application. 🤓
+
+///
## Create models with Decimals
@@ -142,7 +151,10 @@ 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.
+/// warning
- But decimals are supported by most of the other SQL databases. 🎉
+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.
+
+But decimals are supported by most of the other SQL databases. 🎉
+
+///
diff --git a/docs/databases.md b/docs/databases.md
index f1aaf66..54d5e4b 100644
--- a/docs/databases.md
+++ b/docs/databases.md
@@ -1,9 +1,12 @@
# Intro to Databases
-!!! info
- Are you a seasoned developer and already know everything about databases? 🤓
+/// info
- Then you can skip to the [Tutorial - User Guide: First Steps](tutorial/index.md){.internal-link target=_blank} right away.
+Are you a seasoned developer and already know everything about databases? 🤓
+
+Then you can skip to the [Tutorial - User Guide: First Steps](tutorial/index.md){.internal-link target=_blank} right away.
+
+///
If you don't know everything about databases, here's a quick overview.
@@ -17,8 +20,11 @@ So, what is a database?
A **database** is a system to store and manage data in a structured and very efficient way.
-!!! tip
- It's very common to abbreviate the word "database" as **"DB"**.
+/// tip
+
+It's very common to abbreviate the word "database" as **"DB"**.
+
+///
As there's a lot of information about databases, and it can get very technical and academic, I'll give you a quick overview about some of the main concepts here.
@@ -28,8 +34,11 @@ I'll even tell you a bit about different types of databases, including the ones
When starting to program, it might **not be obvious** why having a database apart from the code for your program is a **good idea**. Let's start with that.
-!!! tip
- If that's obvious to you, just continue in the next section below. 👇
+/// tip
+
+If that's obvious to you, just continue in the next section below. 👇
+
+///
In your code you already have **variables**, **dictionaries**, **lists**, etc. They all store **data** in some way already. Why would you need to have a separate database?
@@ -308,8 +317,11 @@ Next, it receives the data and puts it in Python objects that you can continue t
I'll tell you more about SQL, SQLModel, how to use them, and how they are related in the next sections.
-!!! info "Technical Details"
- SQLModel is built on top of SQLAlchemy. It is, in fact, just SQLAlchemy and Pydantic mixed together with some sugar on top.
+/// info | Technical Details
+
+SQLModel is built on top of SQLAlchemy. It is, in fact, just SQLAlchemy and Pydantic mixed together with some sugar on top.
+
+///
## NoSQL Databases
diff --git a/docs/db-to-code.md b/docs/db-to-code.md
index 980c457..537c583 100644
--- a/docs/db-to-code.md
+++ b/docs/db-to-code.md
@@ -172,8 +172,11 @@ The difference in the final SQL statement is subtle, but it changes the meaning
SELECT * FROM hero WHERE id = "2; DROP TABLE hero;";
```
-!!! tip
- Notice the double quotes (`"`) making it a string instead of more raw SQL.
+/// tip
+
+Notice the double quotes (`"`) making it a string instead of more raw SQL.
+
+///
The database will not find any record with that ID:
@@ -187,8 +190,11 @@ Then your code will continue to execute and calmly tell the user that it couldn'
But we never deleted the `hero` table. 🎉
-!!! info
- Of course, there are also other ways to do SQL data sanitization without using a tool like **SQLModel**, but it's still a nice feature you get by default.
+/// info
+
+Of course, there are also other ways to do SQL data sanitization without using a tool like **SQLModel**, but it's still a nice feature you get by default.
+
+///
### Editor Support
@@ -291,8 +297,11 @@ There are many ORMs available apart from **SQLModel**, you can read more about s
## SQL Table Names
-!!! info "Technical Background"
- This is a bit of boring background for SQL purists. Feel free to skip this section. 😉
+/// info | Technical Background
+
+This is a bit of boring background for SQL purists. Feel free to skip this section. 😉
+
+///
When working with pure SQL, it's common to name the tables in plural. So, the table would be named `heroes` instead of `hero`, because it could contain multiple rows, each with one hero.
@@ -304,5 +313,8 @@ You will see **your own code** a lot more than the internal table names, so it's
So, to keep things consistent, I'll keep using the same table names that **SQLModel** would have generated.
-!!! tip
- You can also override the table name. You can read about it in the Advanced User Guide.
+/// tip
+
+You can also override the table name. You can read about it in the Advanced User Guide.
+
+///
diff --git a/docs/features.md b/docs/features.md
index 102edef..f84606b 100644
--- a/docs/features.md
+++ b/docs/features.md
@@ -40,12 +40,15 @@ You won't need to keep guessing the types of different attributes in your models
-!!! info
- Don't worry, adopting this in-development standard only affects/improves editor support.
+/// info
- It doesn't affect performance or correctness. And if the in-progress standard was deprecated your code won't be affected.
+Don't worry, adopting this in-development standard only affects/improves editor support.
- Meanwhile, you will get inline errors (like type checks) and autocompletion on places you wouldn't get with any other library. 🎉
+It doesn't affect performance or correctness. And if the in-progress standard was deprecated your code won't be affected.
+
+Meanwhile, you will get inline errors (like type checks) and autocompletion on places you wouldn't get with any other library. 🎉
+
+///
## Short
diff --git a/docs/help.md b/docs/help.md
index d0d2308..8dc524b 100644
--- a/docs/help.md
+++ b/docs/help.md
@@ -157,12 +157,15 @@ And if there's any other style or consistency need, I'll ask directly for that,
* Then **comment** saying that you did that, that's how I will know you really checked it.
-!!! info
- Unfortunately, I can't simply trust PRs that just have several approvals.
+/// info
- Several times it has happened that there are PRs with 3, 5 or more approvals, probably because the description is appealing, but when I check the PRs, they are actually broken, have a bug, or don't solve the problem they claim to solve. 😅
+Unfortunately, I can't simply trust PRs that just have several approvals.
- So, it's really important that you actually read and run the code, and let me know in the comments that you did. 🤓
+Several times it has happened that there are PRs with 3, 5 or more approvals, probably because the description is appealing, but when I check the PRs, they are actually broken, have a bug, or don't solve the problem they claim to solve. 😅
+
+So, it's really important that you actually read and run the code, and let me know in the comments that you did. 🤓
+
+///
* If the PR can be simplified in a way, you can ask for that, but there's no need to be too picky, there might be a lot of subjective points of view (and I will have my own as well 🙈), so it's better if you can focus on the fundamental things.
@@ -209,10 +212,13 @@ If you can help me with that, **you are helping me maintain SQLModel** and makin
Join the 👥 FastAPI and Friends Discord chat server 👥 and hang out with others in the community. There's a `#sqlmodel` channel.
-!!! tip
- For questions, ask them in GitHub Discussions, there's a much better chance you will receive help there.
+/// tip
- Use the chat only for other general conversations.
+For questions, ask them in GitHub Discussions, there's a much better chance you will receive help there.
+
+Use the chat only for other general conversations.
+
+///
### Don't use the chat for questions
diff --git a/docs/tutorial/automatic-id-none-refresh.md b/docs/tutorial/automatic-id-none-refresh.md
index c7cf975..e9ac7fd 100644
--- a/docs/tutorial/automatic-id-none-refresh.md
+++ b/docs/tutorial/automatic-id-none-refresh.md
@@ -445,10 +445,13 @@ Hero 3: age=48 id=3 name='Rusty-Man' secret_name='Tommy Sharp'
Now let's review all this code once again.
-!!! tip
- Each one of the numbered bubbles shows what each line will print in the output.
+/// tip
- And as we created the **engine** with `echo=True`, we can see the SQL statements being executed at each step.
+Each one of the numbered bubbles shows what each line will print in the output.
+
+And as we created the **engine** with `echo=True`, we can see the SQL statements being executed at each step.
+
+///
```{ .python .annotate }
{!./docs_src/tutorial/automatic_id_none_refresh/tutorial002.py!}
diff --git a/docs/tutorial/code-structure.md b/docs/tutorial/code-structure.md
index 502c8bf..0152ff6 100644
--- a/docs/tutorial/code-structure.md
+++ b/docs/tutorial/code-structure.md
@@ -149,10 +149,13 @@ Let's say that for some reason you hate the idea of having all the database mode
You can also do it. 😎 There's a couple of things to keep in mind. 🤓
-!!! warning
- This is a bit more advanced.
+/// warning
- If the solution above already worked for you, that might be enough for you, and you can continue in the next chapter. 🤓
+This is a bit more advanced.
+
+If the solution above already worked for you, that might be enough for you, and you can continue in the next chapter. 🤓
+
+///
Let's assume that now the file structure is:
diff --git a/docs/tutorial/connect/create-connected-rows.md b/docs/tutorial/connect/create-connected-rows.md
index beda24a..0803432 100644
--- a/docs/tutorial/connect/create-connected-rows.md
+++ b/docs/tutorial/connect/create-connected-rows.md
@@ -37,8 +37,11 @@ Each row in the table `hero` will point to a row in the table `team`:
-!!! info
- We will later update **Spider-Boy** to add him to the **Preventers** team too, but not yet.
+/// info
+
+We will later update **Spider-Boy** to add him to the **Preventers** team too, but not yet.
+
+///
We will continue with the code in the previous example and we will add more things to it.
diff --git a/docs/tutorial/connect/create-connected-tables.md b/docs/tutorial/connect/create-connected-tables.md
index 5a9a420..5500fcc 100644
--- a/docs/tutorial/connect/create-connected-tables.md
+++ b/docs/tutorial/connect/create-connected-tables.md
@@ -126,8 +126,11 @@ This is the name of the **table** in the database, so it is `"team"`, not the na
If you had a custom table name, you would use that custom table name.
-!!! info
- You can learn about setting a custom table name for a model in the Advanced User Guide.
+/// info
+
+You can learn about setting a custom table name for a model in the Advanced User Guide.
+
+///
### Create the Tables
@@ -167,8 +170,11 @@ And as before, we'll call this function from another function `main()`, and we'l
## Run the Code
-!!! tip
- Before running the code, make sure you delete the file `database.db` to make sure you start from scratch.
+/// tip
+
+Before running the code, make sure you delete the file `database.db` to make sure you start from scratch.
+
+///
If we run the code we have up to now, it will go and create the database file `database.db` and the tables in it we just defined, `team` and `hero`:
diff --git a/docs/tutorial/connect/index.md b/docs/tutorial/connect/index.md
index 76e0c7b..aa57e43 100644
--- a/docs/tutorial/connect/index.md
+++ b/docs/tutorial/connect/index.md
@@ -6,7 +6,10 @@ But the main advantage and feature of SQL databases is being able to handle rela
Let's see how to use **SQLModel** to manage connected data in the next chapters. 🤝
-!!! tip
- We will extend this further in the next group of chapters making it even more convenient to work with in Python code, using **relationship attributes**.
+/// tip
- But you should start in this group of chapters first. 🤓
+We will extend this further in the next group of chapters making it even more convenient to work with in Python code, using **relationship attributes**.
+
+But you should start in this group of chapters first. 🤓
+
+///
diff --git a/docs/tutorial/connect/read-connected-data.md b/docs/tutorial/connect/read-connected-data.md
index 0ef3bcc..91bafc4 100644
--- a/docs/tutorial/connect/read-connected-data.md
+++ b/docs/tutorial/connect/read-connected-data.md
@@ -62,8 +62,11 @@ FROM hero, team
WHERE hero.team_id = team.id
```
-!!! info
- Because we have two columns called `name`, one for `hero` and one for `team`, we can specify them with the prefix of the table name and the dot to make it explicit what we refer to.
+/// info
+
+Because we have two columns called `name`, one for `hero` and one for `team`, we can specify them with the prefix of the table name and the dot to make it explicit what we refer to.
+
+///
Notice that now in the `WHERE` part we are not comparing one column with a literal value (like `hero.name = "Deadpond"`), but we are comparing two columns.
@@ -99,14 +102,17 @@ You can go ahead and try it in **DB Browser for SQLite**:
-!!! note
- Wait, what about Spider-Boy? 😱
+/// note
- He doesn't have a team, so his `team_id` is `NULL` in the database. And this SQL is comparing that `NULL` from the `team_id` with all the `id` fields in the rows in the `team` table.
+Wait, what about Spider-Boy? 😱
- As there's no team with an ID of `NULL`, it doesn't find a match.
+He doesn't have a team, so his `team_id` is `NULL` in the database. And this SQL is comparing that `NULL` from the `team_id` with all the `id` fields in the rows in the `team` table.
- But we'll see how to fix that later with a `LEFT JOIN`.
+As there's no team with an ID of `NULL`, it doesn't find a match.
+
+But we'll see how to fix that later with a `LEFT JOIN`.
+
+///
## Select Related Data with **SQLModel**
@@ -164,10 +170,13 @@ For each iteration in the `for` loop we get a a tuple with an instance of the cl
And in this `for` loop we assign them to the variable `hero` and the variable `team`.
-!!! info
- There was a lot of research, design, and work behind **SQLModel** to make this provide the best possible developer experience.
+/// info
- And you should get autocompletion and inline errors in your editor for both `hero` and `team`. 🎉
+There was a lot of research, design, and work behind **SQLModel** to make this provide the best possible developer experience.
+
+And you should get autocompletion and inline errors in your editor for both `hero` and `team`. 🎉
+
+///
## Add It to Main
@@ -281,10 +290,13 @@ Also in **DB Browser for SQLite**:
-!!! tip
- Why bother with all this if the result is the same?
+/// tip
- This `JOIN` will be useful in a bit to be able to also get Spider-Boy, even if he doesn't have a team.
+Why bother with all this if the result is the same?
+
+This `JOIN` will be useful in a bit to be able to also get Spider-Boy, even if he doesn't have a team.
+
+///
## Join Tables in **SQLModel**
@@ -420,8 +432,11 @@ And that would return the following result, including **Spider-Boy** 🎉:
-!!! tip
- The only difference between this query and the previous is that extra `LEFT OUTER`.
+/// tip
+
+The only difference between this query and the previous is that extra `LEFT OUTER`.
+
+///
And here's another of the SQL variations, you could write `LEFT OUTER JOIN` or just `LEFT JOIN`, it means the same.
diff --git a/docs/tutorial/create-db-and-table-with-db-browser.md b/docs/tutorial/create-db-and-table-with-db-browser.md
index 4437f15..72be6db 100644
--- a/docs/tutorial/create-db-and-table-with-db-browser.md
+++ b/docs/tutorial/create-db-and-table-with-db-browser.md
@@ -42,8 +42,11 @@ Click the button New Database.
A dialog should show up. Go to the [project directory you created](./index.md#create-a-project){.internal-link target=_blank} and save the file with a name of `database.db`.
-!!! tip
- It's common to save SQLite database files with an extension of `.db`. Sometimes also `.sqlite`.
+/// tip
+
+It's common to save SQLite database files with an extension of `.db`. Sometimes also `.sqlite`.
+
+///
## Create a Table
diff --git a/docs/tutorial/create-db-and-table.md b/docs/tutorial/create-db-and-table.md
index d0d2742..48341b9 100644
--- a/docs/tutorial/create-db-and-table.md
+++ b/docs/tutorial/create-db-and-table.md
@@ -33,8 +33,11 @@ The first thing we need to do is create a class to represent the data in the tab
A class like this that represents some data is commonly called a **model**.
-!!! tip
- That's why this package is called `SQLModel`. Because it's mainly used to create **SQL Models**.
+/// tip
+
+That's why this package is called `SQLModel`. Because it's mainly used to create **SQL Models**.
+
+///
For that, we will import `SQLModel` (plus other things we will also use) and create a class `Hero` that inherits from `SQLModel` and represents the **table model** for our heroes:
@@ -57,10 +60,13 @@ This class `Hero` **represents the table** for our heroes. And each instance we
We use the config `table=True` to tell **SQLModel** that this is a **table model**, it represents a table.
-!!! info
- It's also possible to have models without `table=True`, those would be only **data models**, without a table in the database, they would not be **table models**.
+/// info
- Those **data models** will be **very useful later**, but for now, we'll just keep adding the `table=True` configuration.
+It's also possible to have models without `table=True`, those would be only **data models**, without a table in the database, they would not be **table models**.
+
+Those **data models** will be **very useful later**, but for now, we'll just keep adding the `table=True` configuration.
+
+///
## Define the Fields, Columns
@@ -112,8 +118,11 @@ And we also set the default value of `age` to `None`.
-!!! tip
- We also define `id` with `Optional`. But we will talk about `id` below.
+/// tip
+
+We also define `id` with `Optional`. But we will talk about `id` below.
+
+///
This way, we tell **SQLModel** that `age` is not required when validating data and that it has a default value of `None`.
@@ -121,10 +130,13 @@ And we also tell it that, in the SQL database, the default value of `age` is `NU
So, this column is "nullable" (can be set to `NULL`).
-!!! info
- In terms of **Pydantic**, `age` is an **optional field**.
+/// info
- In terms of **SQLAlchemy**, `age` is a **nullable column**.
+In terms of **Pydantic**, `age` is an **optional field**.
+
+In terms of **SQLAlchemy**, `age` is a **nullable column**.
+
+///
### Primary Key `id`
@@ -207,10 +219,13 @@ Creating the **engine** is very simple, just call `create_engine()` with a URL f
You should normally have a single **engine** object for your whole application and re-use it everywhere.
-!!! tip
- There's another related thing called a **Session** that normally should *not* be a single object per application.
+/// tip
- But we will talk about it later.
+There's another related thing called a **Session** that normally should *not* be a single object per application.
+
+But we will talk about it later.
+
+///
### Engine Database URL
@@ -272,8 +287,11 @@ engine = create_engine(sqlite_url)
### Engine Technical Details
-!!! tip
- If you didn't know about SQLAlchemy before and are just learning **SQLModel**, you can probably skip this section, scroll below.
+/// tip
+
+If you didn't know about SQLAlchemy before and are just learning **SQLModel**, you can probably skip this section, scroll below.
+
+///
You can read a lot more about the engine in the SQLAlchemy documentation.
@@ -289,12 +307,15 @@ Now everything is in place to finally create the database and table:
{!./docs_src/tutorial/create_db_and_table/tutorial001.py!}
```
-!!! tip
- Creating the engine doesn't create the `database.db` file.
+/// tip
- But once we run `SQLModel.metadata.create_all(engine)`, it creates the `database.db` file **and** creates the `hero` table in that database.
+Creating the engine doesn't create the `database.db` file.
- Both things are done in this single step.
+But once we run `SQLModel.metadata.create_all(engine)`, it creates the `database.db` file **and** creates the `hero` table in that database.
+
+Both things are done in this single step.
+
+///
Let's unwrap that:
@@ -404,8 +425,11 @@ Put the code it in a file `app.py` if you haven't already.
-!!! tip
- Remember to [activate the virtual environment](./index.md#create-a-python-virtual-environment){.internal-link target=_blank} before running it.
+/// tip
+
+Remember to [activate the virtual environment](./index.md#create-a-python-virtual-environment){.internal-link target=_blank} before running it.
+
+///
Now run the program with Python:
@@ -442,20 +466,23 @@ INFO Engine COMMIT
-!!! info
- I simplified the output above a bit to make it easier to read.
+/// info
- But in reality, instead of showing:
+I simplified the output above a bit to make it easier to read.
- ```
- INFO Engine BEGIN (implicit)
- ```
+But in reality, instead of showing:
- it would show something like:
+```
+INFO Engine BEGIN (implicit)
+```
- ```
- 2021-07-25 21:37:39,175 INFO sqlalchemy.engine.Engine BEGIN (implicit)
- ```
+it would show something like:
+
+```
+2021-07-25 21:37:39,175 INFO sqlalchemy.engine.Engine BEGIN (implicit)
+```
+
+///
### `TEXT` or `VARCHAR`
@@ -479,8 +506,11 @@ Additional to the difference between those two data types, some databases like M
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.
-!!! tip
- You will learn how to change the maximum length of string columns later in the Advanced Tutorial - User Guide.
+/// tip
+
+You will learn how to change the maximum length of string columns later in the Advanced Tutorial - User Guide.
+
+///
### Verify the Database
@@ -519,8 +549,11 @@ We don't want that to happen like that, only when we **intend** it to happen, th
Now we would be able to, for example, import the `Hero` class in some other file without having those **side effects**.
-!!! tip
- 😅 **Spoiler alert**: The function is called `create_db_and_tables()` because we will have more **tables** in the future with other classes apart from `Hero`. 🚀
+/// tip
+
+😅 **Spoiler alert**: The function is called `create_db_and_tables()` because we will have more **tables** in the future with other classes apart from `Hero`. 🚀
+
+///
### Create Data as a Script
@@ -528,10 +561,13 @@ We prevented the side effects when importing something from your `app.py` file.
But we still want it to **create the database and table** when we call it with Python directly as an independent script from the terminal, just as as above.
-!!! tip
- Think of the word **script** and **program** as interchangeable.
+/// tip
- The word **script** often implies that the code could be run independently and easily. Or in some cases it refers to a relatively simple program.
+Think of the word **script** and **program** as interchangeable.
+
+The word **script** often implies that the code could be run independently and easily. Or in some cases it refers to a relatively simple program.
+
+///
For that we can use the special variable `__name__` in an `if` block:
@@ -559,10 +595,13 @@ $ python app.py
from app import Hero
```
-!!! tip
- That `if` block using `if __name__ == "__main__":` is sometimes called the "**main block**".
+/// tip
- The official name (in the Python docs) is "**Top-level script environment**".
+That `if` block using `if __name__ == "__main__":` is sometimes called the "**main block**".
+
+The official name (in the Python docs) is "**Top-level script environment**".
+
+///
#### More details
@@ -614,8 +653,11 @@ if __name__ == "__main__":
...will **not** be executed.
-!!! info
- For more information, check the official Python docs.
+/// info
+
+For more information, check the official Python docs.
+
+///
## Last Review
@@ -631,8 +673,11 @@ Now, let's give the code a final look:
{!./docs_src/tutorial/create_db_and_table/annotations/en/tutorial003.md!}
-!!! tip
- Review what each line does by clicking each number bubble in the code. 👆
+/// tip
+
+Review what each line does by clicking each number bubble in the code. 👆
+
+///
## Recap
diff --git a/docs/tutorial/delete.md b/docs/tutorial/delete.md
index 590b2ec..34dd3be 100644
--- a/docs/tutorial/delete.md
+++ b/docs/tutorial/delete.md
@@ -333,8 +333,11 @@ Now let's review all that code:
{!./docs_src/tutorial/delete/annotations/en/tutorial002.md!}
-!!! tip
- Check out the number bubbles to see what is done by each line of code.
+/// tip
+
+Check out the number bubbles to see what is done by each line of code.
+
+///
## Recap
diff --git a/docs/tutorial/fastapi/limit-and-offset.md b/docs/tutorial/fastapi/limit-and-offset.md
index 8802f4e..1152101 100644
--- a/docs/tutorial/fastapi/limit-and-offset.md
+++ b/docs/tutorial/fastapi/limit-and-offset.md
@@ -8,8 +8,11 @@ So, we probably want to limit it.
Let's use the same **offset** and **limit** we learned about in the previous tutorial chapters for the API.
-!!! info
- In many cases, this is also called **pagination**.
+/// info
+
+In many cases, this is also called **pagination**.
+
+///
## Add a Limit and Offset to the Query Parameters
@@ -46,12 +49,15 @@ So, to prevent it, we add additional validation to the `limit` query parameter,
This way, a client can decide to take fewer heroes if they want, but not more.
-!!! info
- If you need to refresh how query parameters and their validation work, check out the docs in FastAPI:
+/// info
- * Query Parameters
- * Query Parameters and String Validations
- * Path Parameters and Numeric Validations
+If you need to refresh how query parameters and their validation work, check out the docs in FastAPI:
+
+* Query Parameters
+* Query Parameters and String Validations
+* Path Parameters and Numeric Validations
+
+///
## Check the Docs UI
diff --git a/docs/tutorial/fastapi/multiple-models.md b/docs/tutorial/fastapi/multiple-models.md
index 6845b98..3833f81 100644
--- a/docs/tutorial/fastapi/multiple-models.md
+++ b/docs/tutorial/fastapi/multiple-models.md
@@ -136,8 +136,11 @@ But `HeroCreate` and `HeroRead` don't have `table = True`. They are only **data
This also means that `SQLModel.metadata.create_all()` won't create tables in the database for `HeroCreate` and `HeroRead`, because they don't have `table = True`, which is exactly what we want. 🚀
-!!! tip
- We will improve this code to avoid duplicating the fields, but for now we can continue learning with these models.
+/// tip
+
+We will improve this code to avoid duplicating the fields, but for now we can continue learning with these models.
+
+///
## Use Multiple Models to Create a Hero
@@ -208,10 +211,13 @@ And now that we return it, FastAPI will validate the data with the `response_mod
This will validate that all the data that we promised is there and will remove any data we didn't declare.
-!!! tip
- 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.
+/// tip
- You can read more about it in the FastAPI docs about Response Model.
+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.
+
+You can read more about it in the FastAPI docs about Response Model.
+
+///
In particular, it will make sure that the `id` is there and that it is indeed an integer (and not `None`).
diff --git a/docs/tutorial/fastapi/read-one.md b/docs/tutorial/fastapi/read-one.md
index 8eea648..b06ebc2 100644
--- a/docs/tutorial/fastapi/read-one.md
+++ b/docs/tutorial/fastapi/read-one.md
@@ -8,8 +8,11 @@ Let's add a new *path operation* to read one single hero.
We want to get the hero based on the `id`, so we will use a **path parameter** `hero_id`.
-!!! info
- If you need to refresh how *path parameters* work, including their data validation, check the FastAPI docs about Path Parameters.
+/// info
+
+If you need to refresh how *path parameters* work, including their data validation, check the FastAPI docs about Path Parameters.
+
+///
```Python hl_lines="8"
{!./docs_src/tutorial/fastapi/read_one/tutorial001.py[ln:1-4]!}
diff --git a/docs/tutorial/fastapi/response-model.md b/docs/tutorial/fastapi/response-model.md
index c019f45..29899be 100644
--- a/docs/tutorial/fastapi/response-model.md
+++ b/docs/tutorial/fastapi/response-model.md
@@ -100,10 +100,13 @@ Additionally, because the schemas are defined in using a standard, there are man
For example, client generators, that can automatically create the code necessary to talk to your API in many languages.
-!!! info
- If you are curious about the standards, FastAPI generates OpenAPI, that internally uses JSON Schema.
+/// info
- You can read about all that in the FastAPI docs - First Steps.
+If you are curious about the standards, FastAPI generates OpenAPI, that internally uses JSON Schema.
+
+You can read about all that in the FastAPI docs - First Steps.
+
+///
## Recap
diff --git a/docs/tutorial/fastapi/session-with-dependency.md b/docs/tutorial/fastapi/session-with-dependency.md
index 195c2e1..d4265af 100644
--- a/docs/tutorial/fastapi/session-with-dependency.md
+++ b/docs/tutorial/fastapi/session-with-dependency.md
@@ -81,14 +81,17 @@ We import `Depends()` from `fastapi`. Then we use it in the *path operation func
-!!! tip
- Here's a tip about that `*,` thing in the parameters.
+/// tip
- Here we are passing the parameter `session` that has a "default value" of `Depends(get_session)` before the parameter `hero`, that doesn't have any default value.
+Here's a tip about that `*,` thing in the parameters.
- Python would normally complain about that, but we can use the initial "parameter" `*,` to mark all the rest of the parameters as "keyword only", which solves the problem.
+Here we are passing the parameter `session` that has a "default value" of `Depends(get_session)` before the parameter `hero`, that doesn't have any default value.
- You can read more about it in the FastAPI documentation Path Parameters and Numeric Validations - Order the parameters as you need, tricks
+Python would normally complain about that, but we can use the initial "parameter" `*,` to mark all the rest of the parameters as "keyword only", which solves the problem.
+
+You can read more about it in the FastAPI documentation Path Parameters and Numeric Validations - Order the parameters as you need, tricks
+
+///
The value of a dependency will **only be used for one request**, FastAPI will call it right before calling your code and will give you the value from that dependency.
diff --git a/docs/tutorial/fastapi/simple-hero-api.md b/docs/tutorial/fastapi/simple-hero-api.md
index 53a5fa7..8debe57 100644
--- a/docs/tutorial/fastapi/simple-hero-api.md
+++ b/docs/tutorial/fastapi/simple-hero-api.md
@@ -62,10 +62,13 @@ But here we will make sure we don't share the same **session** in more than one
And we also need to disable it because in **FastAPI** each request could be handled by multiple interacting threads.
-!!! info
- That's enough information for now, you can read more about it in the FastAPI docs for `async` and `await`.
+/// info
- The main point is, by ensuring you **don't share** the same **session** with more than one request, the code is already safe.
+That's enough information for now, you can read more about it in the FastAPI docs for `async` and `await`.
+
+The main point is, by ensuring you **don't share** the same **session** with more than one request, the code is already safe.
+
+///
## **FastAPI** App
@@ -119,8 +122,11 @@ This should be called only once at startup, not before every request, so we put
## Create Heroes *Path Operation*
-!!! info
- If you need a refresher on what a **Path Operation** is (an endpoint with a specific HTTP Operation) and how to work with it in FastAPI, check out the FastAPI First Steps docs.
+/// info
+
+If you need a refresher on what a **Path Operation** is (an endpoint with a specific HTTP Operation) and how to work with it in FastAPI, check out the FastAPI First Steps docs.
+
+///
Let's create the **path operation** code to create a new hero.
@@ -143,12 +149,15 @@ It will be called when a user sends a request with a `POST` **operation** to the
-!!! info
- If you need a refresher on some of those concepts, checkout the FastAPI documentation:
+/// info
- * First Steps
- * Path Parameters - Data Validation and Data Conversion
- * Request Body
+If you need a refresher on some of those concepts, checkout the FastAPI documentation:
+
+* First Steps
+* Path Parameters - Data Validation and Data Conversion
+* Request Body
+
+///
## The **SQLModel** Advantage
@@ -162,8 +171,11 @@ And then, because this same **SQLModel** object is not only a **Pydantic** model
So we can use intuitive standard Python **type annotations**, and we don't have to duplicate a lot of the code for the database models and the API data models. 🎉
-!!! tip
- We will improve this further later, but for now, it already shows the power of having **SQLModel** classes be both **SQLAlchemy** models and **Pydantic** models at the same time.
+/// tip
+
+We will improve this further later, but for now, it already shows the power of having **SQLModel** classes be both **SQLAlchemy** models and **Pydantic** models at the same time.
+
+///
## Read Heroes *Path Operation*
@@ -226,11 +238,14 @@ $ uvicorn main:app
-!!! info
- The command `uvicorn main:app` refers to:
+/// info
- * `main`: the file `main.py` (the Python "module").
- * `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
+The command `uvicorn main:app` refers to:
+
+* `main`: the file `main.py` (the Python "module").
+* `app`: the object created inside of `main.py` with the line `app = FastAPI()`.
+
+///
### Uvicorn `--reload`
diff --git a/docs/tutorial/fastapi/tests.md b/docs/tutorial/fastapi/tests.md
index cc6ad65..ea08433 100644
--- a/docs/tutorial/fastapi/tests.md
+++ b/docs/tutorial/fastapi/tests.md
@@ -71,8 +71,11 @@ Let's start with a simple test, with just the basic test code we need the check
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/annotations/en/test_main_001.md!}
-!!! tip
- Check out the number bubbles to see what is done by each line of code.
+/// tip
+
+Check out the number bubbles to see what is done by each line of code.
+
+///
That's the **core** of the code we need for all the tests later.
@@ -116,8 +119,11 @@ That way we protect the production database and we have better control of the da
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/annotations/en/test_main_002.md!}
-!!! tip
- Check out the number bubbles to see what is done by each line of code.
+/// tip
+
+Check out the number bubbles to see what is done by each line of code.
+
+///
## Create the Engine and Session for Testing
@@ -197,8 +203,11 @@ We just have to change a couple of parameters in the **engine**.
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/annotations/en/test_main_004.md!}
-!!! tip
- Check out the number bubbles to see what is done by each line of code.
+/// tip
+
+Check out the number bubbles to see what is done by each line of code.
+
+///
That's it, now the test will run using the **in-memory database**, which will be faster and probably safer.
@@ -214,8 +223,11 @@ Do we really have to duplicate all that for **each test**? No, we can do better!
We are using **pytest** to run the tests. And pytest also has a very similar concept to the **dependencies in FastAPI**.
-!!! info
- In fact, pytest was one of the things that inspired the design of the dependencies in FastAPI.
+/// info
+
+In fact, pytest was one of the things that inspired the design of the dependencies in FastAPI.
+
+///
It's a way for us to declare some **code that should be run before** each test and **provide a value** for the test function (that's pretty much the same as FastAPI dependencies).
@@ -237,8 +249,11 @@ Let's see the first code example with a fixture:
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/annotations/en/test_main_005.md!}
-!!! tip
- Check out the number bubbles to see what is done by each line of code.
+/// tip
+
+Check out the number bubbles to see what is done by each line of code.
+
+///
**pytest** fixtures work in a very similar way to FastAPI dependencies, but have some minor differences:
@@ -274,8 +289,11 @@ So, we can create a **client fixture** that will be used in all the tests, and i
{!./docs_src/tutorial/fastapi/app_testing/tutorial001/annotations/en/test_main_006.md!}
-!!! tip
- Check out the number bubbles to see what is done by each line of code.
+/// tip
+
+Check out the number bubbles to see what is done by each line of code.
+
+///
Now we have a **client fixture** that, in turn, uses the **session fixture**.
@@ -306,10 +324,13 @@ Let's add some more tests:
-!!! tip
- It's always **good idea** to not only test the normal case, but also that **invalid data**, **errors**, and **corner cases** are handled correctly.
+/// tip
- That's why we add these two extra tests here.
+It's always **good idea** to not only test the normal case, but also that **invalid data**, **errors**, and **corner cases** are handled correctly.
+
+That's why we add these two extra tests here.
+
+///
Now, any additional test functions can be as **simple** as the first one, they just have to **declare the `client` parameter** to get the `TestClient` **fixture** with all the database stuff setup. Nice! 😎
diff --git a/docs/tutorial/fastapi/update.md b/docs/tutorial/fastapi/update.md
index 0b5292b..df04600 100644
--- a/docs/tutorial/fastapi/update.md
+++ b/docs/tutorial/fastapi/update.md
@@ -12,10 +12,13 @@ So, we need to have all those fields **marked as optional**.
And because the `HeroBase` has some of them as *required* and not optional, we will need to **create a new model**.
-!!! tip
- Here is one of those cases where it probably makes sense to use an **independent model** instead of trying to come up with a complex tree of models inheriting from each other.
+/// tip
- Because each field is **actually different** (we just change it to `Optional`, but that's already making it different), it makes sense to have them in their own model.
+Here is one of those cases where it probably makes sense to use an **independent model** instead of trying to come up with a complex tree of models inheriting from each other.
+
+Because each field is **actually different** (we just change it to `Optional`, but that's already making it different), it makes sense to have them in their own model.
+
+///
So, let's create this new `HeroUpdate` model:
diff --git a/docs/tutorial/index.md b/docs/tutorial/index.md
index 773ab3b..1e78c9c 100644
--- a/docs/tutorial/index.md
+++ b/docs/tutorial/index.md
@@ -57,8 +57,11 @@ $ cd sqlmodel-tutorial
-!!! tip
- Make sure you don't name it also `sqlmodel`, so that you don't end up overriding the name of the package.
+/// tip
+
+Make sure you don't name it also `sqlmodel`, so that you don't end up overriding the name of the package.
+
+///
### Make sure you have Python
@@ -119,61 +122,68 @@ In very short, a virtual environment is a small directory that contains a copy o
And when you "activate" it, any package that you install, for example with `pip`, will be installed in that virtual environment.
-!!! tip
- There are other tools to manage virtual environments, like Poetry.
+/// tip
- And there are alternatives that are particularly useful for deployment like Docker and other types of containers. In this case, the "virtual environment" is not just the Python standard files and the installed packages, but the whole system.
+There are other tools to manage virtual environments, like Poetry.
+
+And there are alternatives that are particularly useful for deployment like Docker and other types of containers. In this case, the "virtual environment" is not just the Python standard files and the installed packages, but the whole system.
+
+///
Go ahead and create a Python virtual environment for this project. And make sure to also upgrade `pip`.
Here are the commands you could use:
-=== "Linux, macOS, Linux in Windows"
+/// tab | Linux, macOS, Linux in Windows
-