1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
# Create and Connect Rows
We will now **create rows** for each table. ✨
The `team` table will look like this:
<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 Margaret's Bar</td>
</tr>
</table>
And after we finish working with the data in this chapter, the `hero` table will look like this:
<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>null</td>
</tr>
</table>
Each row in the table `hero` will point to a row in the table `team`:
<img alt="table relationships" src="/img/tutorial/relationships/select/relationships2.drawio.svg">
/// 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.
{* ./docs_src/tutorial/connect/create_tables/tutorial001_py310.py ln[0] *}
Make sure you remove the `database.db` file before running the examples to get the same results.
## Create Rows for Teams with **SQLModel**
Let's do the same we did before and define a `create_heroes()` function where we create our heroes.
And now we will also create the teams there. 🎉
Let's start by creating two teams:
{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[29:35] hl[29:35] *}
This would hopefully look already familiar.
We start a **session** in a `with` block using the same **engine** we created above.
Then we create two instances of the model class (in this case `Team`).
Next we add those objects to the **session**.
And finally we **commit** the session to save the changes to the database.
## Add It to Main
Let's not forget to add this function `create_heroes()` to the `main()` function so that we run it when calling the program from the command line:
{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[61:63] hl[63] *}
## Run it
If we run that code we have up to now, it will output:
<div class="termy">
```console
$ python app.py
// Previous output omitted 😉
// Automatically start a transaction
INFO Engine BEGIN (implicit)
// Add the teams to the database
INFO Engine INSERT INTO team (name, headquarters) VALUES (?, ?)
INFO Engine [generated in 0.00050s] ('Preventers', 'Sharp Tower')
INFO Engine INSERT INTO team (name, headquarters) VALUES (?, ?)
INFO Engine [cached since 0.002324s ago] ('Z-Force', 'Sister Margaret's Bar')
INFO Engine COMMIT
```
</div>
You can see in the output that it uses common SQL `INSERT` statements to create the rows.
## Create Rows for Heroes in Code
Now let's create one hero object to start.
As the `Hero` class model now has a field (column, attribute) `team_id`, we can set it by using the ID field from the `Team` objects we just created before:
{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[29:39] hl[38] *}
We haven't committed this hero to the database yet, but there are already a couple of things to pay **attention** to.
If the database already had some teams, we wouldn't even know **what is the ID** that is going to be automatically assigned to each team by the database, for example, we couldn't just guess `1` or `2`.
But once the team is created and committed to the database, we can access the object's `id` field to get that ID.
Accessing an attribute in a model that was just committed, for example with `team_z_force.id`, automatically **triggers a refresh** of the data from the DB in the object, and then exposes the value for that field.
So, even though we are not committing this hero yet, just because we are using `team_z_force.id`, that will trigger some SQL sent to the database to fetch the data for this team.
That line alone would generate an output of:
```
INFO Engine BEGIN (implicit)
INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
FROM team
WHERE team.id = ?
INFO Engine [generated in 0.00025s] (2,)
```
Let's now create two more heroes:
{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[29:50] hl[40:46] *}
When creating `hero_rusty_man`, we are accessing `team_preventers.id`, so that will also trigger a refresh of its data, generating an output of:
```
INFO Engine SELECT team.id AS team_id, team.name AS team_name, team.headquarters AS team_headquarters
FROM team
WHERE team.id = ?
INFO Engine [cached since 0.001795s ago] (1,)
```
There's something else to note. We marked `team_id` as `int | None`, meaning that this could be `NULL` on the database (and `None` in Python).
That means that a hero doesn't have to have a team. And in this case, **Spider-Boy** doesn't have one.
Next we just commit the changes to save them to the database, and that will generate the output:
```
INFO Engine INSERT INTO hero (name, secret_name, age, team_id) VALUES (?, ?, ?, ?)
INFO Engine [generated in 0.00022s] ('Deadpond', 'Dive Wilson', None, 2)
INFO Engine INSERT INTO hero (name, secret_name, age, team_id) VALUES (?, ?, ?, ?)
INFO Engine [cached since 0.0007987s ago] ('Rusty-Man', 'Tommy Sharp', 48, 1)
INFO Engine INSERT INTO hero (name, secret_name, age, team_id) VALUES (?, ?, ?, ?)
INFO Engine [cached since 0.001095s ago] ('Spider-Boy', 'Pedro Parqueador', None, None)
INFO Engine COMMIT
```
## Refresh and Print Heroes
Now let's refresh and print those new heroes to see their new ID pointing to their teams:
{* ./docs_src/tutorial/connect/insert/tutorial001_py310.py ln[29:58] hl[52:54,56:58] *}
If we execute that in the command line, it will output:
<div class="termy">
```console
$ python app.py
// Previous output omitted 😉
// Automatically start a transaction
INFO Engine BEGIN (implicit)
// Refresh the first hero
INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id
FROM hero
WHERE hero.id = ?
INFO Engine [generated in 0.00021s] (1,)
// Refresh the second hero
INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id
FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.001575s ago] (2,)
// Refresh the third hero
INFO Engine SELECT hero.id, hero.name, hero.secret_name, hero.age, hero.team_id
FROM hero
WHERE hero.id = ?
INFO Engine [cached since 0.002518s ago] (3,)
// Print the heroes
Created hero: id=1 secret_name='Dive Wilson' team_id=2 name='Deadpond' age=None
Created hero: id=2 secret_name='Tommy Sharp' team_id=1 name='Rusty-Man' age=48
Created hero: id=3 secret_name='Pedro Parqueador' team_id=None name='Spider-Boy' age=None
```
</div>
They now have their `team_id`s, nice!
## Relationships
Relationships in SQL databases are just made by having **columns in one table** referencing the values in **columns on other tables**.
And here we have treated them just like that, more **column fields**, which is what they actually are behind the scenes in the SQL database.
But later in this tutorial, in the next group of chapters, you will learn about **Relationship Attributes** to make it all a lot easier to work with in code. ✨
|