Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fix proxy model Query.remove_inherited_models()

Fixed #18248 -- proxy models were added to included_inherited_models
in sql.query.Query. The variable is meant to be used for multitable
inheritance only. This mistake caused problems in situations where
proxy model's query was reused.
  • Loading branch information...
commit c2e1ecb4b136016ab2996712aa0583fd91657bc9 1 parent 1b05546
@akaariai akaariai authored
View
13 django/db/models/sql/compiler.py
@@ -261,12 +261,12 @@ def get_default_columns(self, with_aliases=False, col_aliases=None,
result = []
if opts is None:
opts = self.query.model._meta
+ # Skip all proxy to the root proxied model
+ opts = opts.concrete_model._meta
qn = self.quote_name_unless_alias
qn2 = self.connection.ops.quote_name
aliases = set()
only_load = self.deferred_to_columns()
- # Skip all proxy to the root proxied model
- proxied_model = opts.concrete_model
if start_alias:
seen = {None: start_alias}
@@ -277,12 +277,9 @@ def get_default_columns(self, with_aliases=False, col_aliases=None,
try:
alias = seen[model]
except KeyError:
- if model is proxied_model:
- alias = start_alias
- else:
- link_field = opts.get_ancestor_link(model)
- alias = self.query.join((start_alias, model._meta.db_table,
- link_field.column, model._meta.pk.column))
+ link_field = opts.get_ancestor_link(model)
+ alias = self.query.join((start_alias, model._meta.db_table,
+ link_field.column, model._meta.pk.column))
seen[model] = alias
else:
# If we're starting from the base model of the queryset, the
View
15 django/db/models/sql/query.py
@@ -933,21 +933,16 @@ def setup_inherited_models(self):
whereas column determination is a later part, and side-effect, of
as_sql()).
"""
- opts = self.model._meta
+ # Skip all proxy models
+ opts = self.model._meta.concrete_model._meta
root_alias = self.tables[0]
seen = {None: root_alias}
- # Skip all proxy to the root proxied model
- proxied_model = opts.concrete_model
-
for field, model in opts.get_fields_with_model():
if model not in seen:
- if model is proxied_model:
- seen[model] = root_alias
- else:
- link_field = opts.get_ancestor_link(model)
- seen[model] = self.join((root_alias, model._meta.db_table,
- link_field.column, model._meta.pk.column))
+ link_field = opts.get_ancestor_link(model)
+ seen[model] = self.join((root_alias, model._meta.db_table,
+ link_field.column, model._meta.pk.column))
self.included_inherited_models = seen
def remove_inherited_models(self):
View
4 tests/regressiontests/queries/models.py
@@ -10,6 +10,10 @@
class DumbCategory(models.Model):
pass
+class ProxyCategory(DumbCategory):
+ class Meta:
+ proxy = True
+
class NamedCategory(DumbCategory):
name = models.CharField(max_length=10)
View
14 tests/regressiontests/queries/tests.py
@@ -19,7 +19,7 @@
ManagedModel, Member, NamedCategory, Note, Number, Plaything, PointerA,
Ranking, Related, Report, ReservedName, Tag, TvChef, Valid, X, Food, Eaten,
Node, ObjectA, ObjectB, ObjectC, CategoryItem, SimpleCategory,
- SpecialCategory, OneToOneCategory, NullableName)
+ SpecialCategory, OneToOneCategory, NullableName, ProxyCategory)
class BaseQuerysetTest(TestCase):
@@ -1952,3 +1952,15 @@ def test_joined_exclude(self):
DumbCategory.objects.exclude(namedcategory__name__in=['nonexisting']),
[self.nc.pk], attrgetter('pk')
)
+
+class ProxyQueryCleanupTest(TestCase):
+ def test_evaluated_proxy_count(self):
+ """
+ Test that generating the query string doesn't alter the query's state
+ in irreversible ways. Refs #18248.
+ """
+ ProxyCategory.objects.create()
+ qs = ProxyCategory.objects.all()
+ self.assertEqual(qs.count(), 1)
+ str(qs.query)
+ self.assertEqual(qs.count(), 1)
Please sign in to comment.
Something went wrong with that request. Please try again.