diff options
author | Daniel Hillier <daniel.hillier@gmail.com> | 2020-08-08 15:17:36 +1000 |
---|---|---|
committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2020-08-11 12:31:50 +0200 |
commit | 784ed4ada112753c35dd7c6b85686ad1d935b65d (patch) | |
tree | 4dfedac2604b76ff78d0d1c43d0f36085d7f281d /tests | |
parent | 9f74a248039974be2e0571ed034a3c9a735a3b60 (diff) | |
download | django-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.py | 14 | ||||
-rw-r--r-- | tests/select_for_update/tests.py | 32 |
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 |