You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/advanced/advanced-relationships/self-referential.md
+7-7Lines changed: 7 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,11 +16,11 @@ To allow more fine-grained control over it, the `Relationship` constructor allow
16
16
17
17
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.
Using the `sa_relationship_kwargs` parameter, we pass the keyword argument `remote_side='Villain.id'` to the underlying relationship property.
22
22
23
-
/// info
23
+
/// note
24
24
25
25
The `remote_side` parameter accepts a Python-evaluable string when using Declarative. This allows us to reference `Villain.id` even though the class is still being defined.
26
26
@@ -40,23 +40,23 @@ For our purposes, it is necessary that we also provide the `back_populates` para
40
40
41
41
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.
42
42
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: int | None` and `boss: 'Villain' | None`. 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}.
44
44
45
45
## Creating instances
46
46
47
47
Now let's see how we can create villains with a boss:
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.
assertany(minion is ebonite_mew for minion in top_boss_minions) # passes
72
72
```
73
73
74
-
/// info
74
+
/// note
75
75
76
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**.
0 commit comments