summaryrefslogtreecommitdiff
path: root/tests
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 12:31:50 +0200
commit784ed4ada112753c35dd7c6b85686ad1d935b65d (patch)
tree4dfedac2604b76ff78d0d1c43d0f36085d7f281d /tests
parent9f74a248039974be2e0571ed034a3c9a735a3b60 (diff)
downloaddjango-784ed4ada112753c35dd7c6b85686ad1d935b65d.tar.gz
[3.0.x] Fixed #31866 -- Fixed locking proxy models in QuerySet.select_for_update(of=()).
Backport of 60626162f76f26d32a38d18151700cb041201fb3 from master
Diffstat (limited to 'tests')
-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 3622a95c11..70511b09a1 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):
@@ -196,6 +198,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'))
@@ -354,6 +371,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