Skip to content

Commit cf87e7a

Browse files
Fix renamed annotations relying on group by clauses not working
Co-authored-by: Hannes Engelhardt <[email protected]>
1 parent 1fecd9b commit cf87e7a

File tree

3 files changed

+51
-1
lines changed

3 files changed

+51
-1
lines changed

psqlextra/sql.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from collections import OrderedDict
2+
from collections.abc import Iterable
23
from typing import Any, Dict, List, Optional, Tuple, Union
34

45
import django
@@ -7,6 +8,7 @@
78
from django.db import connections, models
89
from django.db.models import Expression, sql
910
from django.db.models.constants import LOOKUP_SEP
11+
from django.db.models.expressions import Ref
1012

1113
from .compiler import PostgresInsertOnConflictCompiler
1214
from .compiler import SQLUpdateCompiler as PostgresUpdateCompiler
@@ -74,6 +76,14 @@ def rename_annotations(self, annotations) -> None:
7476
self.annotation_select_mask.remove(old_name)
7577
self.annotation_select_mask.append(new_name)
7678

79+
if isinstance(self.group_by, Iterable):
80+
for statement in self.group_by:
81+
if not isinstance(statement, Ref):
82+
continue
83+
84+
if statement.refs in annotations: # type: ignore[attr-defined]
85+
statement.refs = annotations[statement.refs] # type: ignore[attr-defined]
86+
7787
self.annotations.clear()
7888
self.annotations.update(new_annotations)
7989

settings.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@
2424
'psqlextra',
2525
'tests',
2626
)
27+
28+
USE_TZ = True
29+
TIME_ZONE = 'UTC'

tests/test_query.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
from datetime import datetime, timezone
2+
13
from django.db import connection, models
2-
from django.db.models import Case, F, Q, Value, When
4+
from django.db.models import Case, F, Min, Q, Value, When
5+
from django.db.models.functions.datetime import TruncSecond
36
from django.test.utils import CaptureQueriesContext, override_settings
47

58
from psqlextra.expressions import HStoreRef
@@ -96,6 +99,40 @@ def test_query_annotate_in_expression():
9699
assert result.is_he_henk == "really henk"
97100

98101

102+
def test_query_annotate_group_by():
103+
"""Tests whether annotations with GROUP BY clauses are properly renamed
104+
when the annotation overwrites a field name."""
105+
106+
model = get_fake_model(
107+
{
108+
"name": models.TextField(),
109+
"timestamp": models.DateTimeField(null=False),
110+
"value": models.IntegerField(),
111+
}
112+
)
113+
114+
timestamp = datetime(2024, 1, 1, 0, 0, 0, 0, tzinfo=timezone.utc)
115+
116+
model.objects.create(name="me", timestamp=timestamp, value=1)
117+
118+
result = (
119+
model.objects.values("name")
120+
.annotate(
121+
timestamp=TruncSecond("timestamp", tzinfo=timezone.utc),
122+
value=Min("value"),
123+
)
124+
.values_list(
125+
"name",
126+
"value",
127+
"timestamp",
128+
)
129+
.order_by("name")
130+
.first()
131+
)
132+
133+
assert result == ("me", 1, timestamp)
134+
135+
99136
def test_query_hstore_value_update_f_ref():
100137
"""Tests whether F(..) expressions can be used in hstore values when
101138
performing update queries."""

0 commit comments

Comments
 (0)