mirror of
https://github.com/django/django.git
synced 2025-02-03 14:16:52 +00:00
07fbc6ae0e
When &'ing or |'ing querysets, wrong values could be cached, and crashes could happen. Thanks Marc Tamlyn for figuring out the problem and writing the patch.
129 lines
5.6 KiB
Python
129 lines
5.6 KiB
Python
from __future__ import absolute_import
|
|
|
|
from django.test import TestCase
|
|
|
|
from .models import Tournament, Organiser, Pool, PoolStyle
|
|
|
|
class ExistingRelatedInstancesTests(TestCase):
|
|
fixtures = ['tournament.json']
|
|
|
|
def test_foreign_key(self):
|
|
with self.assertNumQueries(2):
|
|
tournament = Tournament.objects.get(pk=1)
|
|
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=1))
|
|
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'))
|
|
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 = Tournament.objects.get(pk=1)
|
|
tournament_2 = Tournament.objects.get(pk=2)
|
|
with self.assertNumQueries(1):
|
|
pools = tournament_1.pool_set.all() | tournament_2.pool_set.all()
|
|
related_objects = set(pool.tournament for pool in pools)
|
|
self.assertEqual(related_objects, set((tournament_1, tournament_2)))
|
|
|
|
def test_queryset_or_different_cached_items(self):
|
|
tournament = Tournament.objects.get(pk=1)
|
|
organiser = Organiser.objects.get(pk=1)
|
|
with self.assertNumQueries(1):
|
|
pools = tournament.pool_set.all() | organiser.pool_set.all()
|
|
first = pools.filter(pk=1)[0]
|
|
self.assertIs(first.tournament, tournament)
|
|
self.assertIs(first.organiser, organiser)
|
|
|
|
def test_queryset_or_only_one_with_precache(self):
|
|
tournament_1 = Tournament.objects.get(pk=1)
|
|
tournament_2 = Tournament.objects.get(pk=2)
|
|
# 2 queries here as pool id 3 has tournament 2, which is not cached
|
|
with self.assertNumQueries(2):
|
|
pools = tournament_1.pool_set.all() | Pool.objects.filter(pk=3)
|
|
related_objects = set(pool.tournament for pool in pools)
|
|
self.assertEqual(related_objects, set((tournament_1, tournament_2)))
|
|
# and the other direction
|
|
with self.assertNumQueries(2):
|
|
pools = Pool.objects.filter(pk=3) | tournament_1.pool_set.all()
|
|
related_objects = set(pool.tournament for pool in pools)
|
|
self.assertEqual(related_objects, set((tournament_1, tournament_2)))
|
|
|
|
def test_queryset_and(self):
|
|
tournament = Tournament.objects.get(pk=1)
|
|
organiser = Organiser.objects.get(pk=1)
|
|
with self.assertNumQueries(1):
|
|
pools = tournament.pool_set.all() & organiser.pool_set.all()
|
|
first = pools.filter(pk=1)[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=1)
|
|
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=1)
|
|
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'))
|
|
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=1)
|
|
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'))
|
|
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=2)
|
|
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=2)
|
|
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=2)
|
|
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'))
|
|
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'))
|
|
self.assertIs(pools[1], pools[1].poolstyle.pool)
|
|
self.assertIs(pools[2], pools[2].poolstyle.pool)
|