From 2d6f9f0db70685aac139ffbe32714b5b4401119d Mon Sep 17 00:00:00 2001 From: Mohammad Javad Naderi Date: Fri, 9 Dec 2016 15:33:51 +0330 Subject: [PATCH] - Add a failing test to demonstrate a bug - regenerate migrations, fix test - remove prints - move test to regressions Co-authored-by: Mohammad Javad Naderi Co-authored-by: Brian Kohan --- .../tests/migrations/0001_initial.py | 33 ++++++++++++++- src/polymorphic/tests/models.py | 16 ++++++++ src/polymorphic/tests/test_regression.py | 40 ++++++++++++++++++- 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/src/polymorphic/tests/migrations/0001_initial.py b/src/polymorphic/tests/migrations/0001_initial.py index 773b3a79..ad1e92a7 100644 --- a/src/polymorphic/tests/migrations/0001_initial.py +++ b/src/polymorphic/tests/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.26 on 2025-12-01 11:40 +# Generated by Django 4.2.26 on 2025-12-02 16:47 from django.db import migrations, models import django.db.models.deletion @@ -197,6 +197,17 @@ class Migration(migrations.Migration): 'base_manager_name': 'objects', }, ), + migrations.CreateModel( + name='Participant', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_%(app_label)s.%(class)s_set+', to='contenttypes.contenttype')), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + ), migrations.CreateModel( name='PlainA', fields=[ @@ -591,6 +602,18 @@ class Migration(migrations.Migration): }, bases=('tests.modelshow1_plain',), ), + migrations.CreateModel( + name='UserProfile', + fields=[ + ('participant_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='tests.participant')), + ('name', models.CharField(max_length=100)), + ], + options={ + 'abstract': False, + 'base_manager_name': 'objects', + }, + bases=('tests.participant',), + ), migrations.CreateModel( name='UUIDArtProject', fields=[ @@ -1050,6 +1073,14 @@ class Migration(migrations.Migration): ], bases=('tests.uuidplainb',), ), + migrations.CreateModel( + name='Team', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('team_name', models.CharField(max_length=100)), + ('user_profiles', models.ManyToManyField(related_name='user_teams', to='tests.userprofile')), + ], + ), migrations.CreateModel( name='InlineModelB', fields=[ diff --git a/src/polymorphic/tests/models.py b/src/polymorphic/tests/models.py index 8284bbc2..2933b853 100644 --- a/src/polymorphic/tests/models.py +++ b/src/polymorphic/tests/models.py @@ -519,3 +519,19 @@ class SubclassSelectorProxyConcreteModel(SubclassSelectorProxyModel): class NonPolymorphicParent(PolymorphicModel, Group): test = models.CharField(max_length=30, default="test_non_polymorphic_parent") + + +class Participant(PolymorphicModel): + pass + + +class UserProfile(Participant): + name = models.CharField(max_length=100) + + def __str__(self): + return self.name + + +class Team(models.Model): + team_name = models.CharField(max_length=100) + user_profiles = models.ManyToManyField(UserProfile, related_name="user_teams") diff --git a/src/polymorphic/tests/test_regression.py b/src/polymorphic/tests/test_regression.py index f2d74a18..0aa0cba7 100644 --- a/src/polymorphic/tests/test_regression.py +++ b/src/polymorphic/tests/test_regression.py @@ -1,6 +1,6 @@ from django.test import TestCase -from polymorphic.tests.models import Bottom, Middle, Top +from polymorphic.tests.models import Bottom, Middle, Top, Team, UserProfile class RegressionTests(TestCase): @@ -34,3 +34,41 @@ def test_for_query_result_incomplete_with_inheritance(self): [repr(r) for r in expected_queryset], transform=repr, ) + + def test_pr_254(self): + user_a = UserProfile.objects.create(name="a") + user_b = UserProfile.objects.create(name="b") + user_c = UserProfile.objects.create(name="c") + + team1 = Team.objects.create(team_name="team1") + team1.user_profiles.add(user_a, user_b, user_c) + team1.save() + + team2 = Team.objects.create(team_name="team2") + team2.user_profiles.add(user_c) + team2.save() + + # without prefetch_related, the test passes + my_teams = ( + Team.objects.filter(user_profiles=user_c) + .order_by("team_name") + .prefetch_related("user_profiles") + .distinct() + ) + + self.assertEqual(len(my_teams[0].user_profiles.all()), 3) + + self.assertEqual(len(my_teams[1].user_profiles.all()), 1) + + self.assertEqual(len(my_teams[0].user_profiles.all()), 3) + self.assertEqual(len(my_teams[1].user_profiles.all()), 1) + + # without this "for" loop, the test passes + for _ in my_teams: + pass + + # This time, test fails. PR 254 claim + # with sqlite: 4 != 3 + # with postgresql: 2 != 3 + self.assertEqual(len(my_teams[0].user_profiles.all()), 3) + self.assertEqual(len(my_teams[1].user_profiles.all()), 1)