| 1 | # coding: utf-8 |
| 2 | # test for fault in joins with aggregates |
| 3 | from django.db import models |
| 4 | |
| 5 | class Category(models.Model): |
| 6 | name = models.CharField(max_length=100) |
| 7 | order = models.IntegerField() |
| 8 | |
| 9 | def __unicode__(self): |
| 10 | return self.name |
| 11 | |
| 12 | class Group(models.Model): |
| 13 | category = models.ForeignKey(Category) |
| 14 | name = models.CharField(max_length=300) |
| 15 | |
| 16 | def __unicode__(self): |
| 17 | return self.name |
| 18 | |
| 19 | class Registration(models.Model): |
| 20 | group = models.ForeignKey(Group) |
| 21 | type = models.SmallIntegerField() |
| 22 | time = models.IntegerField() |
| 23 | |
| 24 | __test__ = {'API_TESTS': """ |
| 25 | >>> from django.db.models import Sum |
| 26 | |
| 27 | # the categories are reversely ordered: |
| 28 | >>> Category.objects.order_by('order') |
| 29 | [<Category: Cat 2>, <Category: Cat 1>] |
| 30 | |
| 31 | # all groups order by category.order |
| 32 | >>> qs = Group.objects.order_by('category__order').distinct() |
| 33 | >>> [(group.id, group.category.id) for group in qs] |
| 34 | [(2, 2), (4, 2), (1, 1), (3, 1)] |
| 35 | |
| 36 | # annotated |
| 37 | >>> qs = Group.objects.annotate(sum_time = Sum('registration__time') \ |
| 38 | ).order_by('id') |
| 39 | >>> [(group.id, group.category.id, group.sum_time) for group in qs] |
| 40 | [(1, 1, 3), (2, 2, 12), (3, 1, 48), (4, 2, None)] |
| 41 | |
| 42 | # annotated and ordered |
| 43 | # this fails on PostGres because the ordering column is not included in the |
| 44 | # GROUP BY |
| 45 | >>> qs = Group.objects.annotate(sum_time = Sum('registration__time') \ |
| 46 | ).order_by('category__order') |
| 47 | >>> [(group.id, group.category.id, group.sum_time) for group in qs] |
| 48 | [(2, 2, 12), (4, 2, None), (1, 1, 3), (3, 1, 48)] |
| 49 | |
| 50 | # filtered and ordered |
| 51 | # this is a dummy filter, but it joins the tables so only the ones |
| 52 | # with registrations return |
| 53 | # requires distinct |
| 54 | # also fails on postgres |
| 55 | >>> qs = Group.objects.filter(registration__type__gt=0 \ |
| 56 | ).order_by('category__order').distinct() |
| 57 | >>> [(group.id, group.category.id) for group in qs] |
| 58 | [(2, 2), (1, 1), (3, 1)] |
| 59 | |
| 60 | # filtered, annotated and ordered |
| 61 | # this fails on postgres (missing in group by) |
| 62 | # but also on sqlite: wrong result |
| 63 | # I get this: [(4, 2, 256), (2, 2, 12), (1, 1, 3), (3, 1, 240)] |
| 64 | # the result for group 4 includes all registrations |
| 65 | >>> qs = Group.objects.filter(registration__type__gt=0 \ |
| 66 | ).annotate(sum_time = Sum('registration__time') \ |
| 67 | ).order_by('category__order') |
| 68 | >>> [(group.id, group.category.id, group.sum_time) for group in qs] |
| 69 | [(2, 2, 12), (1, 1, 3), (3, 1, 48)] |
| 70 | >>> qs.query.as_sql() |
| 71 | |
| 72 | # notice how the inner join for the order_by comes after the left outer joins |
| 73 | # putting the inner join first gives the correct result |
| 74 | |
| 75 | # filtered, annotated, but unordered |
| 76 | >>> qs = Group.objects.filter(registration__type__gt=0 \ |
| 77 | ).annotate(sum_time = Sum('registration__time') \ |
| 78 | ).order_by('id') |
| 79 | >>> [(group.id, group.category.id, group.sum_time) for group in qs] |
| 80 | [(1, 1, 3), (2, 2, 12), (3, 1, 48)] |
| 81 | |
| 82 | # annotated but unordered and unfiltered |
| 83 | >>> qs = Group.objects.annotate(sum_time = Sum('registration__time') \ |
| 84 | ).order_by('id') |
| 85 | >>> [(group.id, group.category.id, group.sum_time) for group in qs] |
| 86 | [(1, 1, 3), (2, 2, 12), (3, 1, 48), (4, 2, None)] |
| 87 | |
| 88 | # filtered but unordered |
| 89 | >>> qs = Group.objects.filter(registration__type__gt=0 \ |
| 90 | ).order_by('id').distinct() |
| 91 | >>> [(group.id, group.category.id) for group in qs] |
| 92 | [(1, 1), (2, 2), (3, 1)] |
| 93 | |
| 94 | """} |