from django.db.models import FilteredRelation from django.test import TestCase from .models import Organiser, Pool, PoolStyle, Tournament class ExistingRelatedInstancesTests(TestCase): @classmethod def setUpTestData(cls): cls.t1 = Tournament.objects.create(name="Tourney 1") cls.t2 = Tournament.objects.create(name="Tourney 2") cls.o1 = Organiser.objects.create(name="Organiser 1") cls.p1 = Pool.objects.create( name="T1 Pool 1", tournament=cls.t1, organiser=cls.o1 ) cls.p2 = Pool.objects.create( name="T1 Pool 2", tournament=cls.t1, organiser=cls.o1 ) cls.p3 = Pool.objects.create( name="T2 Pool 1", tournament=cls.t2, organiser=cls.o1 ) cls.p4 = Pool.objects.create( name="T2 Pool 2", tournament=cls.t2, organiser=cls.o1 ) cls.ps1 = PoolStyle.objects.create(name="T1 Pool 2 Style", pool=cls.p2) cls.ps2 = PoolStyle.objects.create(name="T2 Pool 1 Style", pool=cls.p3) cls.ps3 = PoolStyle.objects.create( name="T1 Pool 1/3 Style", pool=cls.p1, another_pool=cls.p3 ) def test_foreign_key(self): with self.assertNumQueries(2): tournament = Tournament.objects.get(pk=self.t1.pk) pool = tournament.pool_set.all()[0] self.assertIs(tournament, pool.tournament) def test_foreign_key_prefetch_related(self): with self.assertNumQueries(2): tournament = Tournament.objects.prefetch_related("pool_set").get( pk=self.t1.pk ) pool = tournament.pool_set.all()[0] self.assertIs(tournament, pool.tournament) def test_foreign_key_multiple_prefetch(self): with self.assertNumQueries(2): tournaments = list( Tournament.objects.prefetch_related("pool_set").order_by("pk") ) pool1 = tournaments[0].pool_set.all()[0] self.assertIs(tournaments[0], pool1.tournament) pool2 = tournaments[1].pool_set.all()[0] self.assertIs(tournaments[1], pool2.tournament) def test_queryset_or(self): tournament_1 = self.t1 tournament_2 = self.t2 with self.assertNumQueries(1): pools = tournament_1.pool_set.all() | tournament_2.pool_set.all() related_objects = {pool.tournament for pool in pools} self.assertEqual(related_objects, {tournament_1, tournament_2}) def test_queryset_or_different_cached_items(self): tournament = self.t1 organiser = self.o1 with self.assertNumQueries(1): pools = tournament.pool_set.all() | organiser.pool_set.all() first = pools.filter(pk=self.p1.pk)[0] self.assertIs(first.tournament, tournament) self.assertIs(first.organiser, organiser) def test_queryset_or_only_one_with_precache(self): tournament_1 = self.t1 tournament_2 = self.t2 # 2 queries here as pool 3 has tournament 2, which is not cached with self.assertNumQueries(2): pools = tournament_1.pool_set.all() | Pool.objects.filter(pk=self.p3.pk) related_objects = {pool.tournament for pool in pools} self.assertEqual(related_objects, {tournament_1, tournament_2}) # and the other direction with self.assertNumQueries(2): pools = Pool.objects.filter(pk=self.p3.pk) | tournament_1.pool_set.all() related_objects = {pool.tournament for pool in pools} self.assertEqual(related_objects, {tournament_1, tournament_2}) def test_queryset_and(self): tournament = self.t1 organiser = self.o1 with self.assertNumQueries(1): pools = tournament.pool_set.all() & organiser.pool_set.all() first = pools.filter(pk=self.p1.pk)[0] self.assertIs(first.tournament, tournament) self.assertIs(first.organiser, organiser) def test_one_to_one(self): with self.assertNumQueries(2): style = PoolStyle.objects.get(pk=self.ps1.pk) pool = style.pool self.assertIs(style, pool.poolstyle) def test_one_to_one_select_related(self): with self.assertNumQueries(1): style = PoolStyle.objects.select_related("pool").get(pk=self.ps1.pk) pool = style.pool self.assertIs(style, pool.poolstyle) def test_one_to_one_multi_select_related(self): with self.assertNumQueries(1): poolstyles = list(PoolStyle.objects.select_related("pool").order_by("pk")) self.assertIs(poolstyles[0], poolstyles[0].pool.poolstyle) self.assertIs(poolstyles[1], poolstyles[1].pool.poolstyle) def test_one_to_one_prefetch_related(self): with self.assertNumQueries(2): style = PoolStyle.objects.prefetch_related("pool").get(pk=self.ps1.pk) pool = style.pool self.assertIs(style, pool.poolstyle) def test_one_to_one_multi_prefetch_related(self): with self.assertNumQueries(2): poolstyles = list(PoolStyle.objects.prefetch_related("pool").order_by("pk")) self.assertIs(poolstyles[0], poolstyles[0].pool.poolstyle) self.assertIs(poolstyles[1], poolstyles[1].pool.poolstyle) def test_reverse_one_to_one(self): with self.assertNumQueries(2): pool = Pool.objects.get(pk=self.p2.pk) style = pool.poolstyle self.assertIs(pool, style.pool) def test_reverse_one_to_one_select_related(self): with self.assertNumQueries(1): pool = Pool.objects.select_related("poolstyle").get(pk=self.p2.pk) style = pool.poolstyle self.assertIs(pool, style.pool) def test_reverse_one_to_one_prefetch_related(self): with self.assertNumQueries(2): pool = Pool.objects.prefetch_related("poolstyle").get(pk=self.p2.pk) style = pool.poolstyle self.assertIs(pool, style.pool) def test_reverse_one_to_one_multi_select_related(self): with self.assertNumQueries(1): pools = list(Pool.objects.select_related("poolstyle").order_by("pk")) self.assertIs(pools[1], pools[1].poolstyle.pool) self.assertIs(pools[2], pools[2].poolstyle.pool) def test_reverse_one_to_one_multi_prefetch_related(self): with self.assertNumQueries(2): pools = list(Pool.objects.prefetch_related("poolstyle").order_by("pk")) self.assertIs(pools[1], pools[1].poolstyle.pool) self.assertIs(pools[2], pools[2].poolstyle.pool) def test_reverse_fk_select_related_multiple(self): with self.assertNumQueries(1): ps = list( PoolStyle.objects.annotate( pool_1=FilteredRelation("pool"), pool_2=FilteredRelation("another_pool"), ) .select_related("pool_1", "pool_2") .order_by("-pk") ) self.assertIs(ps[0], ps[0].pool_1.poolstyle) self.assertIs(ps[0], ps[0].pool_2.another_style) def test_multilevel_reverse_fk_cyclic_select_related(self): with self.assertNumQueries(3): p = list( PoolStyle.objects.annotate( tournament_pool=FilteredRelation("pool__tournament__pool"), ).select_related("tournament_pool", "tournament_pool__tournament") ) self.assertEqual(p[0].tournament_pool.tournament, p[0].pool.tournament) def test_multilevel_reverse_fk_select_related(self): with self.assertNumQueries(2): p = list( Tournament.objects.filter(id=self.t2.id) .annotate( style=FilteredRelation("pool__another_style"), ) .select_related("style") ) self.assertEqual(p[0].style.another_pool, self.p3)