Skip to content

Commit daf3975

Browse files
committed
Some text improvements
1 parent 95df345 commit daf3975

File tree

1 file changed

+13
-13
lines changed

1 file changed

+13
-13
lines changed

docs/advanced/advanced-relationships/self-referential.md

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ In database terms this means having a table with a foreign key reference to the
66

77
Say, for example, we want to introduce a `Villain` class. 😈 Every villain can have a **boss**, who also must be a villain. If a villain is the boss to other villains, we want to call those his **minions**.
88

9-
Let's do this with **SQLModel**. 🤓
9+
Let's implement this with **SQLModel**. 🤓
1010

1111
## Using SQLAlchemy arguments
1212

13-
We already learned a lot about [Relationship attributes](../../tutorial/relationship-attributes/index.md){.internal-link target=_blank} in previous chapters. We know that **SQLModel** is built on top of **SQLAlchemy** and we know that the latter allows defining self-referential relationships (see [their documentation](https://docs.sqlalchemy.org/en/20/orm/self_referential.html){.external-link target=_blank}).
13+
We already learned a lot about [Relationship attributes](../../tutorial/relationship-attributes/index.md){.internal-link target=_blank} in previous chapters. We know that **SQLModel** is built on top of **SQLAlchemy**, which supports defining self-referential relationships (see [their documentation](https://docs.sqlalchemy.org/en/20/orm/self_referential.html){.external-link target=_blank}).
1414

15-
To allow more fine-grained control over it, the `Relationship` constructor allows explicitly passing additional keyword-arguments to the [`sqlalchemy.orm.relationship`](https://docs.sqlalchemy.org/en/20/orm/relationship_api.html#sqlalchemy.orm.relationship){.external-link target=_blank} constructor that is being called under the hood via the `sa_relationship_kwargs` parameter. This is supposed to be a mapping (e.g. a dictionary) of strings representing the SQLAlchemy **parameter names** to the **values** we want to pass through as arguments.
15+
To allow more fine-grained control over it, the `Relationship` constructor allows explicitly passing additional keyword-arguments to the [`sqlalchemy.orm.relationship`](https://docs.sqlalchemy.org/en/20/orm/relationship_api.html#sqlalchemy.orm.relationship){.external-link target=_blank} constructor that is being called under the hood via the `sa_relationship_kwargs` parameter. This should be a mapping (e.g. a dictionary) of strings representing the SQLAlchemy **parameter names** to the **values** we want to pass through as arguments.
1616

1717
Since SQLAlchemy relationships provide the [`remote_side`](https://docs.sqlalchemy.org/en/20/orm/relationship_api.html#sqlalchemy.orm.relationship.params.remote_side){.external-link target=_blank} parameter for just such an occasion, we can leverage that directly to construct the self-referential pattern with minimal code.
1818

1919
{* ./docs_src/advanced/self_referential/tutorial001.py ln[6:18] hl[16] *}
2020

21-
Using the `sa_relationship_kwargs` parameter, we pass the keyword-argument `remote_side='Villain.id'` to the underlying relationship property.
21+
Using the `sa_relationship_kwargs` parameter, we pass the keyword argument `remote_side='Villain.id'` to the underlying relationship property.
2222

2323
/// info
2424

@@ -40,31 +40,31 @@ For our purposes, it is necessary that we also provide the `back_populates` para
4040

4141
In addition, the type annotations were made by enclosing our `Villain` class name in quotes, since we are referencing a class that is not yet fully defined by the time the interpreter reaches those lines. See the chapter on [type annotation strings](../../tutorial/relationship-attributes/type-annotation-strings.md){.internal-link target=_blank} for a detailed explanation.
4242

43-
Finally, as with regular (i.e. non-self-referential) foreign key relationships, it is up to us to decide, whether it makes sense to allow the field to be **empty** or not. In our example, not every villain must have a boss (in fact, we would otherwise introduce a circular reference chain, which would not make sense in this context). Therefore we declare `boss_id: Optional[int]` and `boss: Optional['Villain']`. This is analogous to the `Hero``Team` relationship we saw [in an earlier chapter](../../tutorial/relationship-attributes/define-relationships-attributes.md#relationship-attributes-or-none){.internal-link target=_blank}.
43+
Finally, as with regular (i.e. non-self-referential) foreign key relationships, it is up to us to decide whether it makes sense to allow the field to be **empty** or not. In our example, not every villain must have a boss (in fact, we would otherwise introduce a circular reference chain, which would not make sense in this context). Therefore we declare `boss_id: Optional[int]` and `boss: Optional['Villain']`. This is analogous to the `Hero``Team` relationship we saw [in an earlier chapter](../../tutorial/relationship-attributes/define-relationships-attributes.md#relationship-attributes-or-none){.internal-link target=_blank}.
4444

4545
## Creating instances
4646

47-
Now let us see how we can create villains with a boss:
47+
Now let's see how we can create villains with a boss:
4848

4949
{* ./docs_src/advanced/self_referential/tutorial001.py ln[31:50] hl[34:35] *}
5050

51-
Just as with regular relationships, we can simply pass our boss villain as an argument to the constructor with `boss=thinnus`.
51+
Just as with regular relationships, we can simply pass our boss villain as an argument to the constructor using `boss=thinnus`.
5252

53-
If we only learn that a villain actually had a secret boss after we have already created him, we can just as easily assign him that boss retroactively:
53+
If we later learn that a villain actually had a secret boss after we've already created him, we can just as easily assign that boss retroactively:
5454

5555
{* ./docs_src/advanced/self_referential/tutorial001.py ln[31:32,52:56] hl[52] *}
5656

57-
And if we want to add minions to a boss after the fact, this is as easy as adding items to a Python list (because that's all it is 🤓):
57+
And if we want to add minions to a boss afterward, it's as easy as adding items to a Python list (because that's all it is 🤓):
5858

5959
{* ./docs_src/advanced/self_referential/tutorial001.py ln[31:32,58:69] hl[61] *}
6060

61-
Since our relationships work both ways, we don't even need to add all our `clone_bot_`s to the session individually. Instead we can simply add `ultra_bot` once again and commit the changes. We do need to refresh them all individually though, if we want to get their updated attributes.
61+
Since our relationships work both ways, we don't even need to add all our `clone_bot_`s to the session individually. Instead, we can simply add ultra_bot again and commit the changes. We do need to refresh them individually, though, if we want to access their updated attributes.
6262

6363
## Traversing the relationship graph
6464

65-
By setting up our relationships this way, we can easily go back and forth along the graph representing all relationships we have created so far.
65+
By setting up our relationships this way, we can easily go back and forth along the graph representing all the relationships we've created so far.
6666

67-
For example, we can verify that our `clone_bot_1` has a boss, who has his own boss, and one of that top-boss' minions is `ebonite_mew`:
67+
For example, we can verify that our `clone_bot_1` has a boss, who has his own boss, and that one of that top boss's minions is `ebonite_mew`:
6868

6969
```Python
7070
top_boss_minions = clone_bot_3.boss.boss.minions
@@ -73,6 +73,6 @@ assert any(minion is ebonite_mew for minion in top_boss_minions) # passes
7373

7474
/// info
7575

76-
Notice that we can in fact check for **identity** using `is` as opposed to `==` here, since we are dealing with those exact same objects, not just objects that hold the same **data**.
76+
Notice that we can, in fact, check for **identity** using `is` instead of `==` here, since we are dealing with the exact same objects, not just objects containing the same **data**.
7777

7878
///

0 commit comments

Comments
 (0)