mirror of https://github.com/django/django.git
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.
This commit is contained in:
parent
1b05546bd5
commit
c2e1ecb4b1
|
@ -261,12 +261,12 @@ class SQLCompiler(object):
|
|||
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 @@ class SQLCompiler(object):
|
|||
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
|
||||
|
|
|
@ -933,21 +933,16 @@ class Query(object):
|
|||
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):
|
||||
|
|
|
@ -10,6 +10,10 @@ from django.db import models
|
|||
class DumbCategory(models.Model):
|
||||
pass
|
||||
|
||||
class ProxyCategory(DumbCategory):
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
||||
class NamedCategory(DumbCategory):
|
||||
name = models.CharField(max_length=10)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ from .models import (Annotation, Article, Author, Celebrity, Child, Cover,
|
|||
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 @@ class EmptyStringsAsNullTest(TestCase):
|
|||
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)
|
||||
|
|
Loading…
Reference in New Issue