From 3704f6e586063196c64e63e82386b54c8e464434 Mon Sep 17 00:00:00 2001 From: Christoph Buelter Date: Thu, 9 Dec 2021 15:19:56 +0100 Subject: [PATCH 1/4] Add test models and test to replicate the problem The test will fail with v1.3.3 (it passes with v1.3.2) like: AttributeError: 'ManyToManyRel' object has no attribute 'has_default' The problem seems to be that I'm using a ManyToManyField with a specific through table, which I am then making an instance of, passing both its foreignkey fields with the dunder syntax. Passing instances for any of these directly instead will make the test pass. Removing the ManyToManyField will also make the test pass. --- tests/generic/models.py | 18 ++++++++++++++++++ tests/test_filling_fields.py | 12 ++++++++++++ 2 files changed, 30 insertions(+) diff --git a/tests/generic/models.py b/tests/generic/models.py index eacbcacb..04924ea6 100755 --- a/tests/generic/models.py +++ b/tests/generic/models.py @@ -220,6 +220,24 @@ class RelatedNamesWithEmptyDefaultsModel(models.Model): ) +class AspectRatio(models.Model): + name = models.CharField(max_length=128) + + +class PlayerContent(models.Model): + player = models.ForeignKey("Player", on_delete=models.CASCADE) + content = models.ForeignKey("Content", on_delete=models.CASCADE) + + +class Content(models.Model): + aspect_ratio = models.ForeignKey(AspectRatio, on_delete=models.CASCADE) + + +class Player(models.Model): + aspect_ratio = models.ForeignKey(AspectRatio, on_delete=models.CASCADE) + playlist = models.ManyToManyField(Content, through=PlayerContent) + + class ModelWithOverridedSave(Dog): def save(self, *args, **kwargs): self.owner = kwargs.pop("owner") diff --git a/tests/test_filling_fields.py b/tests/test_filling_fields.py index 11589556..f44fbd35 100644 --- a/tests/test_filling_fields.py +++ b/tests/test_filling_fields.py @@ -329,6 +329,18 @@ def test_filling_optional_foreignkey_implicitly(self): assert dummy.cake.name == "Carrot cake" +@pytest.mark.django_db +def test_filling_foreignkeys_on_through_table_with_dunder_syntax(): + aspect_ratio = baker.make(models.AspectRatio, name="16:9") + dummy = baker.make( + models.PlayerContent, + content__aspect_ratio=aspect_ratio, + player__aspect_ratio=aspect_ratio, + ) + assert dummy.content.aspect_ratio.name == "16:9" + assert dummy.player.aspect_ratio.name == "16:9" + + @pytest.mark.django_db class TestsFillingFileField: def test_filling_file_field(self): From 40298779b96fff0cb091dcdb503505655b336e93 Mon Sep 17 00:00:00 2001 From: Christoph Buelter Date: Thu, 9 Dec 2021 15:25:43 +0100 Subject: [PATCH 2/4] Simplify test models, the extra FK isn't needed as it seems --- tests/generic/models.py | 16 ++++++---------- tests/test_filling_fields.py | 9 ++++----- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/tests/generic/models.py b/tests/generic/models.py index 04924ea6..63f5ccb3 100755 --- a/tests/generic/models.py +++ b/tests/generic/models.py @@ -220,22 +220,18 @@ class RelatedNamesWithEmptyDefaultsModel(models.Model): ) -class AspectRatio(models.Model): +class Player(models.Model): name = models.CharField(max_length=128) - - -class PlayerContent(models.Model): - player = models.ForeignKey("Player", on_delete=models.CASCADE) - content = models.ForeignKey("Content", on_delete=models.CASCADE) + playlist = models.ManyToManyField("Content", through="PlayerContent") class Content(models.Model): - aspect_ratio = models.ForeignKey(AspectRatio, on_delete=models.CASCADE) + name = models.CharField(max_length=128) -class Player(models.Model): - aspect_ratio = models.ForeignKey(AspectRatio, on_delete=models.CASCADE) - playlist = models.ManyToManyField(Content, through=PlayerContent) +class PlayerContent(models.Model): + player = models.ForeignKey(Player, on_delete=models.CASCADE) + content = models.ForeignKey(Content, on_delete=models.CASCADE) class ModelWithOverridedSave(Dog): diff --git a/tests/test_filling_fields.py b/tests/test_filling_fields.py index f44fbd35..0bb50984 100644 --- a/tests/test_filling_fields.py +++ b/tests/test_filling_fields.py @@ -331,14 +331,13 @@ def test_filling_optional_foreignkey_implicitly(self): @pytest.mark.django_db def test_filling_foreignkeys_on_through_table_with_dunder_syntax(): - aspect_ratio = baker.make(models.AspectRatio, name="16:9") dummy = baker.make( models.PlayerContent, - content__aspect_ratio=aspect_ratio, - player__aspect_ratio=aspect_ratio, + content__name="Indiana Jones", + player__name="TV" ) - assert dummy.content.aspect_ratio.name == "16:9" - assert dummy.player.aspect_ratio.name == "16:9" + assert dummy.content.name == "Indiana Jones" + assert dummy.player.name == "TV" @pytest.mark.django_db From 75bb8e439a3c0494a5645c1d08ecdb364add53d9 Mon Sep 17 00:00:00 2001 From: Christoph Buelter Date: Fri, 10 Dec 2021 18:12:02 +0100 Subject: [PATCH 3/4] Run black against test file --- tests/test_filling_fields.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/test_filling_fields.py b/tests/test_filling_fields.py index 0bb50984..c7433681 100644 --- a/tests/test_filling_fields.py +++ b/tests/test_filling_fields.py @@ -332,9 +332,7 @@ def test_filling_optional_foreignkey_implicitly(self): @pytest.mark.django_db def test_filling_foreignkeys_on_through_table_with_dunder_syntax(): dummy = baker.make( - models.PlayerContent, - content__name="Indiana Jones", - player__name="TV" + models.PlayerContent, content__name="Indiana Jones", player__name="TV" ) assert dummy.content.name == "Indiana Jones" assert dummy.player.name == "TV" From 9e40a4e481fbe1ec340c36d6c838dbf1be2bcec4 Mon Sep 17 00:00:00 2001 From: Christoph Buelter Date: Fri, 10 Dec 2021 18:18:51 +0100 Subject: [PATCH 4/4] Run tox'ed black against model file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Running black locally in the venv had no effect (⇀‸↼) --- tests/generic/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/generic/models.py b/tests/generic/models.py index 63f5ccb3..25d27ff7 100755 --- a/tests/generic/models.py +++ b/tests/generic/models.py @@ -345,7 +345,6 @@ class DummyImageFieldModel(models.Model): fs = FileSystemStorage(location=gettempdir()) image_field = models.ImageField(upload_to="%Y/%m/%d", storage=fs) - else: # doesn't matter, won't be using class DummyImageFieldModel(models.Model):