Skip to content

Commit 3512586

Browse files
WaVEVtimgraham
authored andcommitted
fix group by for EmbeddedModel field
1 parent 620b8ef commit 3512586

File tree

2 files changed

+42
-2
lines changed

2 files changed

+42
-2
lines changed

django_mongodb_backend/compiler.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def _get_column_from_expression(self, expr, alias):
5353
Create a column named `alias` from the given expression to hold the
5454
aggregate value.
5555
"""
56-
column_target = expr.output_field.__class__()
56+
column_target = expr.output_field.clone()
5757
column_target.db_column = alias
5858
column_target.set_attributes_from_name(alias)
5959
return Col(self.collection_name, column_target)
@@ -81,7 +81,7 @@ def _prepare_expressions_for_pipeline(self, expression, target, annotation_group
8181
alias = (
8282
f"__aggregation{next(annotation_group_idx)}" if sub_expr != expression else target
8383
)
84-
column_target = sub_expr.output_field.__class__()
84+
column_target = sub_expr.output_field.clone()
8585
column_target.db_column = alias
8686
column_target.set_attributes_from_name(alias)
8787
inner_column = Col(self.collection_name, column_target)

tests/model_fields_/test_embedded_model.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import operator
2+
13
from django.core.exceptions import ValidationError
24
from django.db import models
5+
from django.db.models import ExpressionWrapper, F, Max, Sum
36
from django.test import SimpleTestCase, TestCase
47
from django.test.utils import isolate_apps
58

@@ -100,6 +103,43 @@ def test_order_by_embedded_field(self):
100103
qs = Holder.objects.filter(data__integer__gt=3).order_by("-data__integer")
101104
self.assertSequenceEqual(qs, list(reversed(self.objs[4:])))
102105

106+
def test_order_and_group_by_embedded_field(self):
107+
# Create and sort test data by `data__integer`.
108+
expected_objs = sorted(
109+
(Holder.objects.create(data=Data(integer=x)) for x in range(6)),
110+
key=lambda x: x.data.integer,
111+
)
112+
# Group by `data__integer + 5` and get the latest `data__auto_now`
113+
# datetime.
114+
qs = (
115+
Holder.objects.annotate(
116+
group=ExpressionWrapper(F("data__integer") + 5, output_field=models.IntegerField()),
117+
)
118+
.values("group")
119+
.annotate(max_auto_now=Max("data__auto_now"))
120+
.order_by("data__integer")
121+
)
122+
# Each unique `data__integer` is correctly grouped and annotated.
123+
self.assertSequenceEqual(
124+
[{**e, "max_auto_now": e["max_auto_now"]} for e in qs],
125+
[
126+
{"group": e.data.integer + 5, "max_auto_now": truncate_ms(e.data.auto_now)}
127+
for e in expected_objs
128+
],
129+
)
130+
131+
def test_order_and_group_by_embedded_field_annotation(self):
132+
# Create repeated `data__integer` values.
133+
[Holder.objects.create(data=Data(integer=x)) for x in range(6)]
134+
# Group by `data__integer` and compute the sum of occurrences.
135+
qs = (
136+
Holder.objects.values("data__integer")
137+
.annotate(sum=Sum("data__integer"))
138+
.order_by("sum")
139+
)
140+
# The sum is twice the integer values since each appears twice.
141+
self.assertQuerySetEqual(qs, [0, 2, 4, 6, 8, 10], operator.itemgetter("sum"))
142+
103143
def test_nested(self):
104144
obj = Book.objects.create(
105145
author=Author(name="Shakespeare", age=55, address=Address(city="NYC", state="NY"))

0 commit comments

Comments
 (0)