Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
4.1 KiB
Define Relationships Attributes
Now we are finally in one of the most exciting parts of SQLModel.
Relationship Attributes. ✨
We currently have a team
table:
id | name | headquarters |
---|---|---|
1 | Preventers | Sharp Tower |
2 | Z-Force | Sister Margaret’s Bar |
And a hero
table:
id | name | secret_name | age | team_id |
---|---|---|---|---|
1 | Deadpond | Dive Wilson | null | 2 |
2 | Rusty-Man | Tommy Sharp | 48 | 1 |
3 | Spider-Boy | Pedro Parqueador | null | 1 |
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()
:
{!./docs_src/tutorial/connect/insert/tutorial001.py[ln:1-18]!}
# Code below omitted 👇
👀 Full file preview
{!./docs_src/tutorial/connect/insert/tutorial001.py!}
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
:
{!./docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001.py[ln:1-3]!}
# Code below omitted 👇
👀 Full file preview
{!./docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001.py!}
Next, use that Relationship
to declare a new attribute in the model classes:
{!./docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001.py[ln:1-21]!}
# Code below omitted 👇
👀 Full file preview
{!./docs_src/tutorial/relationship_attributes/define_relationship_attributes/tutorial001.py!}
What Are These Relationship Attributes
These 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
:
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. ✨