From 42bc039d3590eec7dab5299462f717be288726a1 Mon Sep 17 00:00:00 2001 From: berin Date: Thu, 31 Mar 2022 19:45:42 -0300 Subject: [PATCH] Get ManyToOneRel fields (reverse FK) back to work (#300) * Get ManyToOneRel fields (reverse FK) back to work * Update changelog * Run linter * Grammar fix 1 Co-authored-by: Tim Klein * Grammar fix 2 Co-authored-by: Tim Klein * Code linter Co-authored-by: Tim Klein --- CHANGELOG.md | 2 ++ model_bakery/baker.py | 13 ++++++++++++- tests/generic/models.py | 17 +++++++++++++++++ tests/test_baker.py | 16 ++++++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 499ba3c2..befc01f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,10 +15,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Extend type hints in `model_bakery.recipe` module, make `Recipe` class generic [PR #292](https://github.com/model-bakers/model_bakery/pull/292) - Explicitly add _fill_optional parameters to baker.make and baker.prepare to aid IDE autocomplete function. [PR #264](https://github.com/model-bakers/model_bakery/pull/264) - Fixed errors with reverse M2M relationships [PR #299](https://github.com/model-bakers/model_bakery/pull/299) +- Fixed errors with reverse M2O relationships [PR #300](https://github.com/model-bakers/model_bakery/pull/300) - Improve exception message for unknown field types [PR #301](https://github.com/model-bakers/model_bakery/pull/301) ### Removed + ## [1.4.0](https://pypi.org/project/model-bakery/1.4.0/) ### Added diff --git a/model_bakery/baker.py b/model_bakery/baker.py index c7065b51..0f2ec28c 100644 --- a/model_bakery/baker.py +++ b/model_bakery/baker.py @@ -606,7 +606,18 @@ def _handle_one_to_many(self, instance: Model, attrs: Dict[str, Any]): manager = getattr(instance, key) for value in values: - if not value.pk: + # Django will handle any operation to persist nested non-persisted FK because + # save doesn't do so and, thus, raises constraint errors. That's why save() + # only gets called if the object doesn't have a pk and also doesn't hold fk + # pointers. + fks = any( + [ + fk + for fk in value._meta.fields + if isinstance(fk, ForeignKey) or isinstance(fk, OneToOneField) + ] + ) + if not value.pk and not fks: value.save() try: diff --git a/tests/generic/models.py b/tests/generic/models.py index 832f1896..0acf2145 100755 --- a/tests/generic/models.py +++ b/tests/generic/models.py @@ -455,3 +455,20 @@ class NonStandardManager(models.Model): name = models.CharField(max_length=30) manager = models.Manager() + + +# The followin models were added after issue 291 +# Since they don't hold much meaning, they are only numbered ones +class Issue291Model1(models.Model): + pass + + +class Issue291Model2(models.Model): + m2m_model_1 = models.ManyToManyField(Issue291Model1) + + +class Issue291Model3(models.Model): + fk_model_2 = models.ForeignKey( + Issue291Model2, related_name="bazs", on_delete=models.CASCADE + ) + name = models.CharField(max_length=32) diff --git a/tests/test_baker.py b/tests/test_baker.py index f65699c0..21e08aab 100644 --- a/tests/test_baker.py +++ b/tests/test_baker.py @@ -569,6 +569,22 @@ def test_field_lookup_for_related_field_does_not_work_with_prepare(self): assert not person.pk assert 0 == models.RelatedNamesModel.objects.count() + def test_ensure_reverse_fk_for_many_to_one_is_working(self): + """This is a regression test to make sure issue 291 is fixed""" + fk1, fk2 = baker.prepare( + models.Issue291Model3, fk_model_2=None, name="custom name", _quantity=2 + ) + obj = baker.make( + models.Issue291Model2, + m2m_model_1=[baker.make(models.Issue291Model1)], + bazs=[fk1, fk2], + ) + + assert obj.bazs.count() == 2 + related_1, related_2 = obj.bazs.all() + assert related_1.name == "custom name" + assert related_2.name == "custom name" + @pytest.mark.django_db class TestHandlingUnsupportedModels: