sqlmodel/docs/tutorial/relationship-attributes/define-relationships-attributes.md
Sebastián Ramírez 6d1d86ab85 📝 Add docs
2021-08-24 15:02:48 +02:00

136 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Define Relationships Attributes
Now we are finally in one of the most exciting parts of **SQLModel**.
Relationship Attributes. ✨
We currently have a `team` table:
<table>
<tr>
<th>id</th><th>name</th><th>headquarters</th>
</tr>
<tr>
<td>1</td><td>Preventers</td><td>Sharp Tower</td>
</tr>
<tr>
<td>2</td><td>Z-Force</td><td>Sister Margarets Bar</td>
</tr>
</table>
And a `hero` table:
<table>
<tr>
<th>id</th><th>name</th><th>secret_name</th><th>age</th><th>team_id</th>
</tr>
<tr>
<td>1</td><td>Deadpond</td><td>Dive Wilson</td><td>null</td><td>2</td>
</tr>
<tr>
<td>2</td><td>Rusty-Man</td><td>Tommy Sharp</td><td>48</td><td>1</td>
</tr>
<tr>
<td>3</td><td>Spider-Boy</td><td>Pedro Parqueador</td><td>null</td><td>1</td>
</tr>
</table>
Now that you know how these tables work underneath and how the model classes represent them, it's time to add a little convenience that will make many operations in code simpler.
## Declare Relationship Attributes
Up to now, we have only used the `team_id` column to connect the tables when querying with `select()`:
```Python hl_lines="18"
{!./docs_src/tutorial/connect/insert/tutorial001.py[ln:1-18]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!./docs_src/tutorial/connect/insert/tutorial001.py!}
```
</details>
This is a **plain field** like all the others, all representing a **column in the table**.
But now let's add a couple of new special attributes to these model classes, let's add `Relationship` attributes.
First, import `Relationship` from `sqlmodel`:
```Python hl_lines="3"
{!./docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001.py[ln:1-3]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!./docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001.py!}
```
</details>
Next, use that `Relationship` to declare a new attribute in the model classes:
```Python hl_lines="11 21"
{!./docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001.py[ln:1-21]!}
# Code below omitted 👇
```
<details>
<summary>👀 Full file preview</summary>
```Python
{!./docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001.py!}
```
</details>
## What Are These Relationship Attributes
This new attributes are not the same as fields, they **don't represent a column** directly in the database, and their value is not a singular value like an integer. Their value is the actual **entire object** that is related.
So, in the case of a `Hero` instance, if you call `hero.team`, you will get the entire `Team` instance object that this hero belongs to. ✨
For example, you could check if a `hero` belongs to any `team` (if `.team` is not `None`) and then print the team's `name`:
```Python
if hero.team:
print(hero.team.name)
```
## Optional Relationship Attributes
Notice that in the `Hero` class, the type annotation for `team` is `Optional[Team]`.
This means that this attribute could be `None`, or it could be a full `Team` object.
This is because the related **`team_id` could also be `None`** (or `NULL` in the database).
If it was required for a `Hero` instance to belong to a `Team`, then the `team_id` would be `int` instead of `Optional[int]`.
And the `team` attribute would be a `Team` instead of `Optional[Team]`.
## Relationship Attributes With Lists
And in the `Team` class, the `heroes` attribute is annotated as a list of `Hero` objects, because that's what it will have.
**SQLModel** (actually SQLAlchemy) is smart enough to know that the relationship is established by the `team_id`, as that's the foreign key that points from the `hero` table to the `team` table, so we don't have to specify that explicitly here.
!!! tip
There's a couple of things we'll check again in some of the next chapters, about the `List["Hero"]` and the `back_populates`.
But for now, let's first see how to use these relationship attributes.
## Next Steps
Now let's see some real examples of how to use these new **relationship attributes** in the next chapters. ✨