|
| 1 | +import operator |
| 2 | + |
1 | 3 | from django.core.exceptions import ValidationError
|
2 | 4 | from django.db import models
|
| 5 | +from django.db.models import ExpressionWrapper, F, Max, Sum |
3 | 6 | from django.test import SimpleTestCase, TestCase
|
4 | 7 | from django.test.utils import isolate_apps
|
5 | 8 |
|
@@ -100,6 +103,43 @@ def test_order_by_embedded_field(self):
|
100 | 103 | qs = Holder.objects.filter(data__integer__gt=3).order_by("-data__integer")
|
101 | 104 | self.assertSequenceEqual(qs, list(reversed(self.objs[4:])))
|
102 | 105 |
|
| 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 | + |
103 | 143 | def test_nested(self):
|
104 | 144 | obj = Book.objects.create(
|
105 | 145 | author=Author(name="Shakespeare", age=55, address=Address(city="NYC", state="NY"))
|
|
0 commit comments