mirror of
				https://github.com/fastapi/sqlmodel.git
				synced 2025-10-31 10:06:57 +08:00 
			
		
		
		
	 e7b970cfa8
			
		
	
	e7b970cfa8
	
	
	
		
			
			Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
		
			
				
	
	
		
			211 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
| # 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. ✨
 |