Fixed #31377 -- Disabled grouping by aliases on QuerySet.values()/values_list() when they collide with field names.

Regression in fb3f034f1c.

Thanks Holovashchenko Vadym for the report.
This commit is contained in:
Hasan Ramezani 2020-03-19 19:54:36 +01:00 committed by Mariusz Felisiak
parent 895f28f9cb
commit 10866a10fe
4 changed files with 35 additions and 1 deletions

View File

@ -1927,6 +1927,19 @@ class Query(BaseExpression):
primary key, and the query would be equivalent, the optimization
will be made automatically.
"""
# Column names from JOINs to check collisions with aliases.
if allow_aliases:
column_names = set()
seen_models = set()
for join in list(self.alias_map.values())[1:]: # Skip base table.
model = join.join_field.related_model
if model not in seen_models:
column_names.update({
field.column
for field in model._meta.local_concrete_fields
})
seen_models.add(model)
group_by = list(self.select)
if self.annotation_select:
for alias, annotation in self.annotation_select.items():
@ -1940,7 +1953,7 @@ class Query(BaseExpression):
warnings.warn(msg, category=RemovedInDjango40Warning)
group_by_cols = annotation.get_group_by_cols()
else:
if not allow_aliases:
if not allow_aliases or alias in column_names:
alias = None
group_by_cols = annotation.get_group_by_cols(alias=alias)
group_by.extend(group_by_cols)

View File

@ -11,3 +11,7 @@ Bugfixes
* Added the ability to handle ``.po`` files containing different plural
equations for the same language (:ticket:`30439`).
* Fixed a regression in Django 3.0 where ``QuerySet.values()`` and
``values_list()`` crashed if a queryset contained an aggregation and
``Subquery()`` annotation that collides with a field name (:ticket:`31377`).

View File

@ -5,6 +5,7 @@ class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
friends = models.ManyToManyField('self', blank=True)
rating = models.FloatField(null=True)
def __str__(self):
return self.name

View File

@ -1191,6 +1191,22 @@ class AggregateTestCase(TestCase):
},
])
def test_aggregation_subquery_annotation_values_collision(self):
books_rating_qs = Book.objects.filter(
publisher=OuterRef('pk'),
price=Decimal('29.69'),
).values('rating')
publisher_qs = Publisher.objects.filter(
book__contact__age__gt=20,
name=self.p1.name,
).annotate(
rating=Subquery(books_rating_qs),
contacts_count=Count('book__contact'),
).values('rating').annotate(total_count=Count('rating'))
self.assertEqual(list(publisher_qs), [
{'rating': 4.0, 'total_count': 2},
])
@skipUnlessDBFeature('supports_subqueries_in_group_by')
@skipIf(
connection.vendor == 'mysql' and 'ONLY_FULL_GROUP_BY' in connection.sql_mode,