summaryrefslogtreecommitdiff
path: root/django/db/models/sql/compiler.py
diff options
context:
space:
mode:
authorAbhijeet Viswa <abhijeetviswa@gmail.com>2020-02-08 10:22:09 +0530
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-02-11 21:37:17 +0100
commit32d89bf11461857fde13017432a586e565b97ecc (patch)
treeeccae487b705497e5b7aafb9f79191dd942b6a46 /django/db/models/sql/compiler.py
parenteeed073aa214d2d2f77297423eead6c87114d56f (diff)
[2.2.x] Fixed #31246 -- Fixed locking models in QuerySet.select_for_update(of=()) for related fields and parent link fields with multi-table inheritance.
Partly regression in 0107e3d1058f653f66032f7fd3a0bd61e96bf782. Backport of 1712a76b9dfda1ef220395e62ea87079da8c9f6c from master.
Diffstat (limited to 'django/db/models/sql/compiler.py')
-rw-r--r--django/db/models/sql/compiler.py37
1 files changed, 22 insertions, 15 deletions
diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py
index 9e709d0f6e..e5c726676a 100644
--- a/django/db/models/sql/compiler.py
+++ b/django/db/models/sql/compiler.py
@@ -948,19 +948,34 @@ class SQLCompiler:
the query.
"""
def _get_parent_klass_info(klass_info):
- return (
- {
+ for parent_model, parent_link in klass_info['model']._meta.parents.items():
+ parent_list = parent_model._meta.get_parent_list()
+ yield {
'model': parent_model,
'field': parent_link,
'reverse': False,
'select_fields': [
select_index
for select_index in klass_info['select_fields']
- if self.select[select_index][0].target.model == parent_model
+ # Selected columns from a model or its parents.
+ if (
+ self.select[select_index][0].target.model == parent_model or
+ self.select[select_index][0].target.model in parent_list
+ )
],
}
- for parent_model, parent_link in klass_info['model']._meta.parents.items()
- )
+
+ def _get_first_selected_col_from_model(klass_info):
+ """
+ Find the first selected column from a model. If it doesn't exist,
+ don't lock a model.
+
+ select_fields is filled recursively, so it also contains fields
+ from the parent models.
+ """
+ for select_index in klass_info['select_fields']:
+ if self.select[select_index][0].target.model == klass_info['model']:
+ return self.select[select_index][0]
def _get_field_choices():
"""Yield all allowed field paths in breadth-first search order."""
@@ -989,14 +1004,7 @@ class SQLCompiler:
for name in self.query.select_for_update_of:
klass_info = self.klass_info
if name == 'self':
- # Find the first selected column from a base model. If it
- # doesn't exist, don't lock a base model.
- for select_index in klass_info['select_fields']:
- if self.select[select_index][0].target.model == klass_info['model']:
- col = self.select[select_index][0]
- break
- else:
- col = None
+ col = _get_first_selected_col_from_model(klass_info)
else:
for part in name.split(LOOKUP_SEP):
klass_infos = (
@@ -1016,8 +1024,7 @@ class SQLCompiler:
if klass_info is None:
invalid_names.append(name)
continue
- select_index = klass_info['select_fields'][0]
- col = self.select[select_index][0]
+ col = _get_first_selected_col_from_model(klass_info)
if col is not None:
if self.connection.features.select_for_update_of_column:
result.append(self.compile(col)[0])