1
from __future__ import absolute_import
4
from decimal import Decimal
6
from django.db.models import Avg, Sum, Count, Max, Min
7
from django.test import TestCase, Approximate
9
from .models import Author, Publisher, Book, Store
12
class BaseAggregateTestCase(TestCase):
13
fixtures = ["aggregation.json"]
15
def test_empty_aggregate(self):
16
self.assertEqual(Author.objects.all().aggregate(), {})
18
def test_single_aggregate(self):
19
vals = Author.objects.aggregate(Avg("age"))
20
self.assertEqual(vals, {"age__avg": Approximate(37.4, places=1)})
22
def test_multiple_aggregates(self):
23
vals = Author.objects.aggregate(Sum("age"), Avg("age"))
24
self.assertEqual(vals, {"age__sum": 337, "age__avg": Approximate(37.4, places=1)})
26
def test_filter_aggregate(self):
27
vals = Author.objects.filter(age__gt=29).aggregate(Sum("age"))
28
self.assertEqual(len(vals), 1)
29
self.assertEqual(vals["age__sum"], 254)
31
def test_related_aggregate(self):
32
vals = Author.objects.aggregate(Avg("friends__age"))
33
self.assertEqual(len(vals), 1)
34
self.assertAlmostEqual(vals["friends__age__avg"], 34.07, places=2)
36
vals = Book.objects.filter(rating__lt=4.5).aggregate(Avg("authors__age"))
37
self.assertEqual(len(vals), 1)
38
self.assertAlmostEqual(vals["authors__age__avg"], 38.2857, places=2)
40
vals = Author.objects.all().filter(name__contains="a").aggregate(Avg("book__rating"))
41
self.assertEqual(len(vals), 1)
42
self.assertEqual(vals["book__rating__avg"], 4.0)
44
vals = Book.objects.aggregate(Sum("publisher__num_awards"))
45
self.assertEqual(len(vals), 1)
46
self.assertEqual(vals["publisher__num_awards__sum"], 30)
48
vals = Publisher.objects.aggregate(Sum("book__price"))
49
self.assertEqual(len(vals), 1)
50
self.assertEqual(vals["book__price__sum"], Decimal("270.27"))
52
def test_aggregate_multi_join(self):
53
vals = Store.objects.aggregate(Max("books__authors__age"))
54
self.assertEqual(len(vals), 1)
55
self.assertEqual(vals["books__authors__age__max"], 57)
57
vals = Author.objects.aggregate(Min("book__publisher__num_awards"))
58
self.assertEqual(len(vals), 1)
59
self.assertEqual(vals["book__publisher__num_awards__min"], 1)
61
def test_aggregate_alias(self):
62
vals = Store.objects.filter(name="Amazon.com").aggregate(amazon_mean=Avg("books__rating"))
63
self.assertEqual(len(vals), 1)
64
self.assertAlmostEqual(vals["amazon_mean"], 4.08, places=2)
66
def test_annotate_basic(self):
67
self.assertQuerysetEqual(
68
Book.objects.annotate().order_by('pk'), [
69
"The Definitive Guide to Django: Web Development Done Right",
70
"Sams Teach Yourself Django in 24 Hours",
71
"Practical Django Projects",
72
"Python Web Development with Django",
73
"Artificial Intelligence: A Modern Approach",
74
"Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp"
79
books = Book.objects.annotate(mean_age=Avg("authors__age"))
83
'The Definitive Guide to Django: Web Development Done Right'
85
self.assertEqual(b.mean_age, 34.5)
87
def test_annotate_m2m(self):
88
books = Book.objects.filter(rating__lt=4.5).annotate(Avg("authors__age")).order_by("name")
89
self.assertQuerysetEqual(
91
('Artificial Intelligence: A Modern Approach', 51.5),
92
('Practical Django Projects', 29.0),
93
('Python Web Development with Django', Approximate(30.3, places=1)),
94
('Sams Teach Yourself Django in 24 Hours', 45.0)
96
lambda b: (b.name, b.authors__age__avg),
99
books = Book.objects.annotate(num_authors=Count("authors")).order_by("name")
100
self.assertQuerysetEqual(
102
('Artificial Intelligence: A Modern Approach', 2),
103
('Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp', 1),
104
('Practical Django Projects', 1),
105
('Python Web Development with Django', 3),
106
('Sams Teach Yourself Django in 24 Hours', 1),
107
('The Definitive Guide to Django: Web Development Done Right', 2)
109
lambda b: (b.name, b.num_authors)
112
def test_backwards_m2m_annotate(self):
113
authors = Author.objects.filter(name__contains="a").annotate(Avg("book__rating")).order_by("name")
114
self.assertQuerysetEqual(
116
('Adrian Holovaty', 4.5),
117
('Brad Dayley', 3.0),
118
('Jacob Kaplan-Moss', 4.5),
119
('James Bennett', 4.0),
120
('Paul Bissex', 4.0),
121
('Stuart Russell', 4.0)
123
lambda a: (a.name, a.book__rating__avg)
126
authors = Author.objects.annotate(num_books=Count("book")).order_by("name")
127
self.assertQuerysetEqual(
129
('Adrian Holovaty', 1),
131
('Jacob Kaplan-Moss', 1),
132
('James Bennett', 1),
133
('Jeffrey Forcier', 1),
136
('Stuart Russell', 1),
137
('Wesley J. Chun', 1)
139
lambda a: (a.name, a.num_books)
142
def test_reverse_fkey_annotate(self):
143
books = Book.objects.annotate(Sum("publisher__num_awards")).order_by("name")
144
self.assertQuerysetEqual(
146
('Artificial Intelligence: A Modern Approach', 7),
147
('Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp', 9),
148
('Practical Django Projects', 3),
149
('Python Web Development with Django', 7),
150
('Sams Teach Yourself Django in 24 Hours', 1),
151
('The Definitive Guide to Django: Web Development Done Right', 3)
153
lambda b: (b.name, b.publisher__num_awards__sum)
156
publishers = Publisher.objects.annotate(Sum("book__price")).order_by("name")
157
self.assertQuerysetEqual(
159
('Apress', Decimal("59.69")),
160
("Jonno's House of Books", None),
161
('Morgan Kaufmann', Decimal("75.00")),
162
('Prentice Hall', Decimal("112.49")),
163
('Sams', Decimal("23.09"))
165
lambda p: (p.name, p.book__price__sum)
168
def test_annotate_values(self):
169
books = list(Book.objects.filter(pk=1).annotate(mean_age=Avg("authors__age")).values())
177
"name": "The Definitive Guide to Django: Web Development Done Right",
179
"price": Approximate(Decimal("30")),
180
"pubdate": datetime.date(2007, 12, 6),
187
books = Book.objects.filter(pk=1).annotate(mean_age=Avg('authors__age')).values('pk', 'isbn', 'mean_age')
198
books = Book.objects.filter(pk=1).annotate(mean_age=Avg("authors__age")).values("name")
202
"name": "The Definitive Guide to Django: Web Development Done Right"
207
books = Book.objects.filter(pk=1).values().annotate(mean_age=Avg('authors__age'))
215
"name": "The Definitive Guide to Django: Web Development Done Right",
217
"price": Approximate(Decimal("30")),
218
"pubdate": datetime.date(2007, 12, 6),
225
books = Book.objects.values("rating").annotate(n_authors=Count("authors__id"), mean_age=Avg("authors__age")).order_by("rating")
236
"mean_age": Approximate(37.16, places=1)
251
authors = Author.objects.annotate(Avg("friends__age")).order_by("name")
252
self.assertEqual(len(authors), 9)
253
self.assertQuerysetEqual(
255
('Adrian Holovaty', 32.0),
256
('Brad Dayley', None),
257
('Jacob Kaplan-Moss', 29.5),
258
('James Bennett', 34.0),
259
('Jeffrey Forcier', 27.0),
260
('Paul Bissex', 31.0),
261
('Peter Norvig', 46.0),
262
('Stuart Russell', 57.0),
263
('Wesley J. Chun', Approximate(33.66, places=1))
265
lambda a: (a.name, a.friends__age__avg)
268
def test_count(self):
269
vals = Book.objects.aggregate(Count("rating"))
270
self.assertEqual(vals, {"rating__count": 6})
272
vals = Book.objects.aggregate(Count("rating", distinct=True))
273
self.assertEqual(vals, {"rating__count": 4})
275
def test_fkey_aggregate(self):
276
explicit = list(Author.objects.annotate(Count('book__id')))
277
implicit = list(Author.objects.annotate(Count('book')))
278
self.assertEqual(explicit, implicit)
280
def test_annotate_ordering(self):
281
books = Book.objects.values('rating').annotate(oldest=Max('authors__age')).order_by('oldest', 'rating')
303
books = Book.objects.values("rating").annotate(oldest=Max("authors__age")).order_by("-oldest", "-rating")
325
def test_aggregate_annotation(self):
326
vals = Book.objects.annotate(num_authors=Count("authors__id")).aggregate(Avg("num_authors"))
327
self.assertEqual(vals, {"num_authors__avg": Approximate(1.66, places=1)})
329
def test_filtering(self):
330
p = Publisher.objects.create(name='Expensive Publisher', num_awards=0)
332
name='ExpensiveBook1',
336
price=Decimal("1000"),
339
pubdate=datetime.date(2008,12,1)
342
name='ExpensiveBook2',
346
price=Decimal("1000"),
349
pubdate=datetime.date(2008,12,2)
352
name='ExpensiveBook3',
359
pubdate=datetime.date(2008,12,3)
362
publishers = Publisher.objects.annotate(num_books=Count("book__id")).filter(num_books__gt=1).order_by("pk")
363
self.assertQuerysetEqual(
367
"Expensive Publisher",
372
publishers = Publisher.objects.filter(book__price__lt=Decimal("40.0")).order_by("pk")
373
self.assertQuerysetEqual(
379
"Expensive Publisher",
384
publishers = Publisher.objects.annotate(num_books=Count("book__id")).filter(num_books__gt=1, book__price__lt=Decimal("40.0")).order_by("pk")
385
self.assertQuerysetEqual(
389
"Expensive Publisher",
394
publishers = Publisher.objects.filter(book__price__lt=Decimal("40.0")).annotate(num_books=Count("book__id")).filter(num_books__gt=1).order_by("pk")
395
self.assertQuerysetEqual(
402
publishers = Publisher.objects.annotate(num_books=Count("book")).filter(num_books__range=[1, 3]).order_by("pk")
403
self.assertQuerysetEqual(
409
"Expensive Publisher",
414
publishers = Publisher.objects.annotate(num_books=Count("book")).filter(num_books__range=[1, 2]).order_by("pk")
415
self.assertQuerysetEqual(
425
publishers = Publisher.objects.annotate(num_books=Count("book")).filter(num_books__in=[1, 3]).order_by("pk")
426
self.assertQuerysetEqual(
430
"Expensive Publisher",
435
publishers = Publisher.objects.annotate(num_books=Count("book")).filter(num_books__isnull=True)
436
self.assertEqual(len(publishers), 0)
438
def test_annotation(self):
439
vals = Author.objects.filter(pk=1).aggregate(Count("friends__id"))
440
self.assertEqual(vals, {"friends__id__count": 2})
442
books = Book.objects.annotate(num_authors=Count("authors__name")).filter(num_authors__ge=2).order_by("pk")
443
self.assertQuerysetEqual(
445
"The Definitive Guide to Django: Web Development Done Right",
446
"Artificial Intelligence: A Modern Approach",
451
authors = Author.objects.annotate(num_friends=Count("friends__id", distinct=True)).filter(num_friends=0).order_by("pk")
452
self.assertQuerysetEqual(
459
publishers = Publisher.objects.annotate(num_books=Count("book__id")).filter(num_books__gt=1).order_by("pk")
460
self.assertQuerysetEqual(
468
publishers = Publisher.objects.filter(book__price__lt=Decimal("40.0")).annotate(num_books=Count("book__id")).filter(num_books__gt=1)
469
self.assertQuerysetEqual(
476
books = Book.objects.annotate(num_authors=Count("authors__id")).filter(authors__name__contains="Norvig", num_authors__gt=1)
477
self.assertQuerysetEqual(
479
"Artificial Intelligence: A Modern Approach",
484
def test_more_aggregation(self):
485
a = Author.objects.get(name__contains='Norvig')
486
b = Book.objects.get(name__contains='Done Right')
490
vals = Book.objects.annotate(num_authors=Count("authors__id")).filter(authors__name__contains="Norvig", num_authors__gt=1).aggregate(Avg("rating"))
491
self.assertEqual(vals, {"rating__avg": 4.25})
493
def test_even_more_aggregate(self):
494
publishers = Publisher.objects.annotate(earliest_book=Min("book__pubdate")).exclude(earliest_book=None).order_by("earliest_book").values()
498
'earliest_book': datetime.date(1991, 10, 15),
501
'name': 'Morgan Kaufmann'
504
'earliest_book': datetime.date(1995, 1, 15),
507
'name': 'Prentice Hall'
510
'earliest_book': datetime.date(2007, 12, 6),
516
'earliest_book': datetime.date(2008, 3, 3),
524
vals = Store.objects.aggregate(Max("friday_night_closing"), Min("original_opening"))
528
"friday_night_closing__max": datetime.time(23, 59, 59),
529
"original_opening__min": datetime.datetime(1945, 4, 25, 16, 24, 14),
533
def test_annotate_values_list(self):
534
books = Book.objects.filter(pk=1).annotate(mean_age=Avg("authors__age")).values_list("pk", "isbn", "mean_age")
537
(1, "159059725", 34.5),
541
books = Book.objects.filter(pk=1).annotate(mean_age=Avg("authors__age")).values_list("isbn")
548
books = Book.objects.filter(pk=1).annotate(mean_age=Avg("authors__age")).values_list("mean_age")
555
books = Book.objects.filter(pk=1).annotate(mean_age=Avg("authors__age")).values_list("mean_age", flat=True)
556
self.assertEqual(list(books), [34.5])
558
books = Book.objects.values_list("price").annotate(count=Count("price")).order_by("-count", "price")
561
(Decimal("29.69"), 2),
562
(Decimal('23.09'), 1),
565
(Decimal('82.8'), 1),
569
def test_dates_with_aggregation(self):
571
Test that .dates() returns a distinct set of dates when applied to a
572
QuerySet with aggregation.
574
Refs #18056. Previously, .dates() would return distinct (date_kind,
575
aggregation) sets, in this case (year, num_authors), so 2008 would be
576
returned twice because there are books from 2008 with a different
579
dates = Book.objects.annotate(num_authors=Count("authors")).dates('pubdate', 'year')
580
self.assertQuerysetEqual(
582
"datetime.date(1991, 1, 1)",
583
"datetime.date(1995, 1, 1)",
584
"datetime.date(2007, 1, 1)",
585
"datetime.date(2008, 1, 1)"