summaryrefslogtreecommitdiff
path: root/tests/select_for_update
diff options
context:
space:
mode:
authorDaniel Hillier <daniel.hillier@gmail.com>2020-08-08 15:17:36 +1000
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-08-11 11:55:10 +0200
commit60626162f76f26d32a38d18151700cb041201fb3 (patch)
treecb1b1cfc019734f6048b2e069e3667b11ce9116e /tests/select_for_update
parent0aeb802cf054cb369646c871b53c93a83c1fa58a (diff)
Fixed #31866 -- Fixed locking proxy models in QuerySet.select_for_update(of=()).
Diffstat (limited to 'tests/select_for_update')
-rw-r--r--tests/select_for_update/models.py14
-rw-r--r--tests/select_for_update/tests.py32
2 files changed, 45 insertions, 1 deletions
diff --git a/tests/select_for_update/models.py b/tests/select_for_update/models.py
index 305e8cac49..0a6396bc70 100644
--- a/tests/select_for_update/models.py
+++ b/tests/select_for_update/models.py
@@ -23,6 +23,20 @@ class EUCity(models.Model):
country = models.ForeignKey(EUCountry, models.CASCADE)
+class CountryProxy(Country):
+ class Meta:
+ proxy = True
+
+
+class CountryProxyProxy(CountryProxy):
+ class Meta:
+ proxy = True
+
+
+class CityCountryProxy(models.Model):
+ country = models.ForeignKey(CountryProxyProxy, models.CASCADE)
+
+
class Person(models.Model):
name = models.CharField(max_length=30)
born = models.ForeignKey(City, models.CASCADE, related_name='+')
diff --git a/tests/select_for_update/tests.py b/tests/select_for_update/tests.py
index 2197596a16..705975b760 100644
--- a/tests/select_for_update/tests.py
+++ b/tests/select_for_update/tests.py
@@ -15,7 +15,9 @@ from django.test import (
)
from django.test.utils import CaptureQueriesContext
-from .models import City, Country, EUCity, EUCountry, Person, PersonProfile
+from .models import (
+ City, CityCountryProxy, Country, EUCity, EUCountry, Person, PersonProfile,
+)
class SelectForUpdateTests(TransactionTestCase):
@@ -206,6 +208,21 @@ class SelectForUpdateTests(TransactionTestCase):
self.assertTrue(self.has_for_update_sql(ctx.captured_queries, of=expected))
@skipUnlessDBFeature('has_select_for_update_of')
+ def test_for_update_sql_model_proxy_generated_of(self):
+ with transaction.atomic(), CaptureQueriesContext(connection) as ctx:
+ list(CityCountryProxy.objects.select_related(
+ 'country',
+ ).select_for_update(
+ of=('country',),
+ ))
+ if connection.features.select_for_update_of_column:
+ expected = ['select_for_update_country"."entity_ptr_id']
+ else:
+ expected = ['select_for_update_country']
+ expected = [connection.ops.quote_name(value) for value in expected]
+ self.assertTrue(self.has_for_update_sql(ctx.captured_queries, of=expected))
+
+ @skipUnlessDBFeature('has_select_for_update_of')
def test_for_update_of_followed_by_values(self):
with transaction.atomic():
values = list(Person.objects.select_for_update(of=('self',)).values('pk'))
@@ -376,6 +393,19 @@ class SelectForUpdateTests(TransactionTestCase):
EUCountry.objects.select_for_update(of=('name',)).get()
@skipUnlessDBFeature('has_select_for_update', 'has_select_for_update_of')
+ def test_model_proxy_of_argument_raises_error_proxy_field_in_choices(self):
+ msg = (
+ 'Invalid field name(s) given in select_for_update(of=(...)): '
+ 'name. Only relational fields followed in the query are allowed. '
+ 'Choices are: self, country, country__entity_ptr.'
+ )
+ with self.assertRaisesMessage(FieldError, msg):
+ with transaction.atomic():
+ CityCountryProxy.objects.select_related(
+ 'country',
+ ).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