diff --git a/docs/relations/foreign-key.md b/docs/relations/foreign-key.md index 1bdc4f4..adc205c 100644 --- a/docs/relations/foreign-key.md +++ b/docs/relations/foreign-key.md @@ -99,7 +99,7 @@ course = Course(name="Math", completed=False) # note - not saved await department.courses.add(course) assert course.pk is not None # child model was saved # relation on child model is set and FK column saved in db -assert courses.department == department +assert course.department == department # relation on parent model is also set assert department.courses[0] == course ``` @@ -112,6 +112,10 @@ assert department.courses[0] == course 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. diff --git a/docs/releases.md b/docs/releases.md index 79d7622..9d72cbd 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -8,10 +8,13 @@ ## 🐛 Fixes * Fix is null filter with pagination and relations (by @erichaydel) [#214](https://github.com/collerek/ormar/issues/214) +* Fix not saving child object on reverse side of the relation if not saved before [#216](https://github.com/collerek/ormar/issues/216) + ## 💬 Other * Expand [fastapi](https://collerek.github.io/ormar/fastapi) part of the documentation to show samples of using ormar in requests and responses in fastapi. +* Improve the docs in regard of `default`, `ForeignKey.add` etc. # 0.10.9 diff --git a/ormar/relations/relation_proxy.py b/ormar/relations/relation_proxy.py index be3258c..baa6812 100644 --- a/ormar/relations/relation_proxy.py +++ b/ormar/relations/relation_proxy.py @@ -214,7 +214,7 @@ class RelationProxy(Generic[T], list): setattr(self._owner, self.field_name, item) else: setattr(item, relation_name, self._owner) - await item.update() + await item.upsert() await self._owner.signals.post_relation_add.send( sender=self._owner.__class__, instance=self._owner, diff --git a/tests/test_queries/db.sqlite b/tests/test_queries/db.sqlite new file mode 100644 index 0000000..80c5b0e Binary files /dev/null and b/tests/test_queries/db.sqlite differ diff --git a/tests/test_queries/test_adding_related.py b/tests/test_queries/test_adding_related.py new file mode 100644 index 0000000..271a13c --- /dev/null +++ b/tests/test_queries/test_adding_related.py @@ -0,0 +1,54 @@ +from typing import Optional + +import databases +import pytest +import sqlalchemy +import asyncio + +import ormar + +from tests.settings import DATABASE_URL + +database = databases.Database(DATABASE_URL) +metadata = sqlalchemy.MetaData() + + +class Department(ormar.Model): + class Meta: + database = database + metadata = metadata + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + + +class Course(ormar.Model): + class Meta: + database = database + metadata = metadata + + id: int = ormar.Integer(primary_key=True) + name: str = ormar.String(max_length=100) + completed: bool = ormar.Boolean(default=False) + department: Optional[Department] = ormar.ForeignKey(Department) + + +@pytest.fixture(autouse=True, scope="module") +def create_test_database(): + engine = sqlalchemy.create_engine(DATABASE_URL) + metadata.drop_all(engine) + metadata.create_all(engine) + yield + metadata.drop_all(engine) + + +@pytest.mark.asyncio +async def test_adding_relation_to_reverse_saves_the_child(): + async with database: + department = await Department(name="Science").save() + course = Course(name="Math", completed=False) + + await department.courses.add(course) + assert course.pk is not None + assert course.department == department + assert department.courses[0] == course