ForeignKey
ForeignKey(to: Model, *, name: str = None, unique: bool = False, nullable: bool = True,
related_name: str = None, virtual: bool = False, onupdate: Union[ReferentialAction, str] = None,
ondelete: Union[ReferentialAction, str] = None, foreign_key_name: str = None, **kwargs: Any)
has required parameters to that takes target Model class.
Sqlalchemy column and type are automatically taken from target Model.
- Sqlalchemy column: class of a target
Modelprimary key column - Type (used for pydantic): type of a target
Model
Defining Models
To define a relation add ForeignKey field that points to related Model.
| Python | |
|---|---|
1 | |
Reverse Relation
ForeignKey fields are automatically registering reverse side of the relation.
By default it's child (source) Model name + s, like courses in snippet below:
| Python | |
|---|---|
1 | |
Reverse relation exposes API to manage related objects also from parent side.
Skipping reverse relation
If you are sure you don't want the reverse relation you can use skip_reverse=True
flag of the ForeignKey.
If you set skip_reverse flag internally the field is still registered on the other
side of the relationship so you can:
filterby related models fields from reverse modelorder_byby related models fields from reverse model
But you cannot:
- Access the related field from reverse model with
related_name - Even if you
select_relatedfrom reverse side of the model the returned models won't be populated in reversed instance (the join is not prevented so you still canfilterandorder_byover the relation) - The relation won't be populated in
model_dump()andmodel_dump_json() - You cannot pass the nested related objects when populating from dictionary or json (also through
fastapi). It will be either ignored or error will be raised depending onextrasetting in pydanticConfig.
Example:
| Python | |
|---|---|
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 | |
add
Adding child model from parent side causes adding related model to currently loaded parent relation, as well as sets child's model foreign key value and updates the model.
| Python | |
|---|---|
1 2 3 4 5 6 7 8 9 | |
Warning
If you want to add child model on related model the primary key value for parent model has to exist in database.
Otherwise ormar will raise RelationshipInstanceError as it cannot set child's ForeignKey column value
if parent model has no primary key value.
That means that in example above the department has to be saved before you can call department.courses.add().
Warning
This method will not work on ManyToMany relations - there, both sides of the relation have to be saved before adding to relation.
remove
Removal of the related model one by one.
In reverse relation calling remove() does not remove the child model, but instead nulls it ForeignKey value.
| Python | |
|---|---|
1 2 3 4 5 6 7 8 9 | |
But if you want to clear the relation and delete the child at the same time you can issue:
| Python | |
|---|---|
1 2 3 | |
clear
Removal of all related models in one call.
Like with remove, by default, clear() nulls the ForeigKey column on child model (all, not matter if they are loaded or not).
| Python | |
|---|---|
1 2 | |
If you want to remove the children altogether from the database, set keep_reversed=False
| Python | |
|---|---|
1 2 | |
QuerysetProxy
Reverse relation exposes QuerysetProxy API that allows you to query related model like you would issue a normal Query.
To read which methods of QuerySet are available read below querysetproxy
related_name
You can overwrite related model field name by providing related_name parameter like below:
| Python | |
|---|---|
1 | |
Tip
The reverse relation on access returns list of wekref.proxy to avoid circular references.
Warning
When you provide multiple relations to the same model ormar can no longer auto generate
the related_name for you. Therefore, in that situation you have to provide related_name
for all but one (one can be default and generated) or all related fields.
Referential Actions
When an object referenced by a ForeignKey is changed (deleted or updated),
ormar will set the SQL constraint specified by the ondelete and onupdate argument.
The possible values for ondelete and onupdate are found in ormar.ReferentialAction:
Note
Instead of ormar.ReferentialAction, you can directly pass string values to these two arguments, but this is not recommended because it will break the integrity.
CASCADE
Whenever rows in the parent (referenced) table are deleted (or updated), the respective rows of the child (referencing) table with a matching foreign key column will be deleted (or updated) as well. This is called a cascade delete (or update).
RESTRICT
A value cannot be updated or deleted when a row exists in a referencing or child table that references the value in the referenced table.
Similarly, a row cannot be deleted as long as there is a reference to it from a referencing or child table.
SET_NULL
Set the ForeignKey to None; this is only possible if nullable is True.
SET_DEFAULT
Set the ForeignKey to its default value; a server_default for the ForeignKey must be set.
Note
Note that the default value is not allowed and you must do this through server_default, which you can read about in this section.
DO_NOTHING
Take NO ACTION; NO ACTION and RESTRICT are very much alike. The main difference between NO ACTION and RESTRICT is that with NO ACTION the referential integrity check is done after trying to alter the table. RESTRICT does the check before trying to execute the UPDATE or DELETE statement. Both referential actions act the same if the referential integrity check fails: the UPDATE or DELETE statement will result in an error.
Overriding the foreign key constraint name
By default ormar generates the foreign key constraint name as
fk_{source_table}_{target_table}_{target_pk}_{field_name}. On databases with a
short identifier length limit (for example MySQL's 64 character limit) the
auto-generated name can be truncated or rejected. Pass foreign_key_name to use
a custom name instead:
| Python | |
|---|---|
1 2 3 4 5 6 7 8 | |
When used on an abstract base class, each subclass suffixes the name with its own tablename to avoid constraint name collisions across sibling tables.
Relation Setup
You have several ways to set-up a relationship connection.
Model instance
The most obvious one is to pass a related Model instance to the constructor.
| Python | |
|---|---|
1 | |
Primary key value
You can setup the relation also with just the pk column value of the related model.
| Python | |
|---|---|
1 | |
Dictionary
Next option is with a dictionary of key-values of the related model.
You can build the dictionary yourself or get it from existing model with model_dump() method.
| Python | |
|---|---|
1 | |
None
Finally you can explicitly set it to None (default behavior if no value passed).
| Python | |
|---|---|
1 | |
You can also clear a ForeignKey relation on an already-loaded model by
assigning None — the field must be nullable for this to persist. The
related model is unregistered from the instance immediately, so subsequent
reads return None without requiring a reload:
| Python | |
|---|---|
1 2 3 4 5 6 7 | |
Note
Assigning None to a non-nullable ForeignKey is ignored at the
in-memory level. Make the field nullable=True (the default) if you
need to unassign it.
Warning
In all not None cases the primary key value for related model has to exist in database.
Otherwise an IntegrityError will be raised by your database driver library.