summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorRan Benita <ran234@gmail.com>2017-10-17 11:28:00 +0800
committerTim Graham <timograham@gmail.com>2017-10-28 20:33:42 -0400
commit03049fb8d96ccd1f1ed0285486103542de42faba (patch)
tree243c0b4cc9b622a47ce7a665d36d8b4ab4973a0d /tests
parent56b364bacca0d6a6cd8fbcd93aeb49f3ad46e58c (diff)
Refs #28010 -- Allowed reverse related fields in SELECT FOR UPDATE .. OF.
Thanks Adam Chidlow for polishing the patch.
Diffstat (limited to 'tests')
-rw-r--r--tests/filtered_relation/tests.py16
-rw-r--r--tests/select_for_update/models.py4
-rw-r--r--tests/select_for_update/tests.py21
3 files changed, 37 insertions, 4 deletions
diff --git a/tests/filtered_relation/tests.py b/tests/filtered_relation/tests.py
index 4bae2216bf..2596dcbdc2 100644
--- a/tests/filtered_relation/tests.py
+++ b/tests/filtered_relation/tests.py
@@ -1,4 +1,4 @@
-from django.db import connection
+from django.db import connection, transaction
from django.db.models import Case, Count, F, FilteredRelation, Q, When
from django.test import TestCase
from django.test.testcases import skipUnlessDBFeature
@@ -62,6 +62,20 @@ class FilteredRelationTests(TestCase):
(self.book4, self.author1),
], lambda x: (x, x.author_join))
+ @skipUnlessDBFeature('has_select_for_update', 'has_select_for_update_of')
+ def test_select_related_foreign_key_for_update_of(self):
+ with transaction.atomic():
+ qs = Book.objects.annotate(
+ author_join=FilteredRelation('author'),
+ ).select_related('author_join').select_for_update(of=('self',)).order_by('pk')
+ with self.assertNumQueries(1):
+ self.assertQuerysetEqual(qs, [
+ (self.book1, self.author1),
+ (self.book2, self.author2),
+ (self.book3, self.author2),
+ (self.book4, self.author1),
+ ], lambda x: (x, x.author_join))
+
def test_without_join(self):
self.assertSequenceEqual(
Author.objects.annotate(
diff --git a/tests/select_for_update/models.py b/tests/select_for_update/models.py
index b04ed31b00..b8154af3df 100644
--- a/tests/select_for_update/models.py
+++ b/tests/select_for_update/models.py
@@ -14,3 +14,7 @@ class Person(models.Model):
name = models.CharField(max_length=30)
born = models.ForeignKey(City, models.CASCADE, related_name='+')
died = models.ForeignKey(City, models.CASCADE, related_name='+')
+
+
+class PersonProfile(models.Model):
+ person = models.OneToOneField(Person, models.CASCADE, related_name='profile')
diff --git a/tests/select_for_update/tests.py b/tests/select_for_update/tests.py
index 707fa0e9ba..6de268cb2b 100644
--- a/tests/select_for_update/tests.py
+++ b/tests/select_for_update/tests.py
@@ -15,7 +15,7 @@ from django.test import (
)
from django.test.utils import CaptureQueriesContext
-from .models import City, Country, Person
+from .models import City, Country, Person, PersonProfile
class SelectForUpdateTests(TransactionTestCase):
@@ -30,6 +30,7 @@ class SelectForUpdateTests(TransactionTestCase):
self.city1 = City.objects.create(name='Liberchies', country=self.country1)
self.city2 = City.objects.create(name='Samois-sur-Seine', country=self.country2)
self.person = Person.objects.create(name='Reinhardt', born=self.city1, died=self.city2)
+ self.person_profile = PersonProfile.objects.create(person=self.person)
# We need another database connection in transaction to test that one
# connection issuing a SELECT ... FOR UPDATE will block.
@@ -225,13 +226,27 @@ class SelectForUpdateTests(TransactionTestCase):
msg = (
'Invalid field name(s) given in select_for_update(of=(...)): %s. '
'Only relational fields followed in the query are allowed. '
- 'Choices are: self, born.'
+ 'Choices are: self, born, profile.'
)
for name in ['born__country', 'died', 'died__country']:
with self.subTest(name=name):
with self.assertRaisesMessage(FieldError, msg % name):
with transaction.atomic():
- Person.objects.select_related('born').select_for_update(of=(name,)).get()
+ Person.objects.select_related(
+ 'born', 'profile',
+ ).exclude(profile=None).select_for_update(of=(name,)).get()
+
+ @skipUnlessDBFeature('has_select_for_update', 'has_select_for_update_of')
+ def test_reverse_one_to_one_of_arguments(self):
+ """
+ Reverse OneToOneFields may be included in of=(...) as long as NULLs
+ are excluded because LEFT JOIN isn't allowed in SELECT FOR UPDATE.
+ """
+ with transaction.atomic():
+ person = Person.objects.select_related(
+ 'profile',
+ ).exclude(profile=None).select_for_update(of=('profile',)).get()
+ self.assertEqual(person.profile, self.person_profile)
@skipUnlessDBFeature('has_select_for_update')
def test_for_update_after_from(self):