示例#1
0
    def test_aggregate_over_complex_annotation(self):
        qs = Author.objects.annotate(
            combined_ages=Sum(F('age') + F('friends__age')))

        age = qs.aggregate(max_combined_age=Max('combined_ages'))
        self.assertEqual(age['max_combined_age'], 176)

        age = qs.aggregate(max_combined_age_doubled=Max('combined_ages') * 2)
        self.assertEqual(age['max_combined_age_doubled'], 176 * 2)

        age = qs.aggregate(max_combined_age_doubled=Max('combined_ages') +
                           Max('combined_ages'))
        self.assertEqual(age['max_combined_age_doubled'], 176 * 2)

        age = qs.aggregate(max_combined_age_doubled=Max('combined_ages') +
                           Max('combined_ages'),
                           sum_combined_age=Sum('combined_ages'))
        self.assertEqual(age['max_combined_age_doubled'], 176 * 2)
        self.assertEqual(age['sum_combined_age'], 954)

        age = qs.aggregate(max_combined_age_doubled=Max('combined_ages') +
                           Max('combined_ages'),
                           sum_combined_age_doubled=Sum('combined_ages') +
                           Sum('combined_ages'))
        self.assertEqual(age['max_combined_age_doubled'], 176 * 2)
        self.assertEqual(age['sum_combined_age_doubled'], 954 * 2)
示例#2
0
 def test_aggregation_expressions(self):
     a1 = Author.objects.aggregate(av_age=Sum('age') / Count('*'))
     a2 = Author.objects.aggregate(av_age=Sum('age') / Count('age'))
     a3 = Author.objects.aggregate(av_age=Avg('age'))
     self.assertEqual(a1, {'av_age': 37})
     self.assertEqual(a2, {'av_age': 37})
     self.assertEqual(a3, {'av_age': Approximate(37.4, places=1)})
示例#3
0
    def test_annotate_values_aggregate(self):
        alias_age = Author.objects.annotate(age_alias=F('age')).values(
            'age_alias', ).aggregate(sum_age=Sum('age_alias'))

        age = Author.objects.values('age').aggregate(sum_age=Sum('age'))

        self.assertEqual(alias_age['sum_age'], age['sum_age'])
示例#4
0
    def test_annotate_over_annotate(self):
        author = Author.objects.annotate(age_alias=F('age')).annotate(
            sum_age=Sum('age_alias')).get(name="Adrian Holovaty")

        other_author = Author.objects.annotate(sum_age=Sum('age')).get(
            name="Adrian Holovaty")

        self.assertEqual(author.sum_age, other_author.sum_age)
示例#5
0
 def test_complex_aggregations_require_kwarg(self):
     with self.assertRaisesMessage(TypeError,
                                   'Complex annotations require an alias'):
         Author.objects.annotate(Sum(F('age') + F('friends__age')))
     with self.assertRaisesMessage(TypeError,
                                   'Complex aggregates require an alias'):
         Author.objects.aggregate(Sum('age') / Count('age'))
     with self.assertRaisesMessage(TypeError,
                                   'Complex aggregates require an alias'):
         Author.objects.aggregate(Sum(1))
示例#6
0
 def test_annotation_in_f_grouped_by_annotation(self):
     qs = (
         Publisher.objects.annotate(multiplier=Value(3))
         # group by option => sum of value * multiplier
         .values('name').annotate(
             multiplied_value_sum=Sum(F('multiplier') *
                                      F('num_awards'))).order_by())
     self.assertCountEqual(qs, [
         {
             'multiplied_value_sum': 9,
             'name': 'Apress'
         },
         {
             'multiplied_value_sum': 0,
             'name': "Jonno's House of Books"
         },
         {
             'multiplied_value_sum': 27,
             'name': 'Morgan Kaufmann'
         },
         {
             'multiplied_value_sum': 21,
             'name': 'Prentice Hall'
         },
         {
             'multiplied_value_sum': 3,
             'name': 'Sams'
         },
     ])
示例#7
0
 def test_annotate(self):
     hs1 = HasLinkThing.objects.create()
     hs2 = HasLinkThing.objects.create()
     HasLinkThing.objects.create()
     b = Board.objects.create(name=str(hs1.pk))
     Link.objects.create(content_object=hs2)
     link = Link.objects.create(content_object=hs1)
     Link.objects.create(content_object=b)
     qs = HasLinkThing.objects.annotate(Sum('links')).filter(pk=hs1.pk)
     # If content_type restriction isn't in the query's join condition,
     # then wrong results are produced here as the link to b will also match
     # (b and hs1 have equal pks).
     self.assertEqual(qs.count(), 1)
     self.assertEqual(qs[0].links__sum, link.id)
     link.delete()
     # Now if we don't have proper left join, we will not produce any
     # results at all here.
     # clear cached results
     qs = qs.all()
     self.assertEqual(qs.count(), 1)
     # Note - 0 here would be a nicer result...
     self.assertIs(qs[0].links__sum, None)
     # Finally test that filtering works.
     self.assertEqual(qs.filter(links__sum__isnull=True).count(), 1)
     self.assertEqual(qs.filter(links__sum__isnull=False).count(), 0)
示例#8
0
 def test_related_aggregates_m2m_and_fk(self):
     q = Q(friends__book__publisher__name='Apress') & ~Q(
         friends__name='test3')
     agg = Sum('friends__book__pages', filter=q)
     self.assertEqual(
         Author.objects.filter(name='test').aggregate(pages=agg)['pages'],
         528)
示例#9
0
 def test_annotation_expressions(self):
     authors = Author.objects.annotate(
         combined_ages=Sum(F('age') + F('friends__age'))).order_by('name')
     authors2 = Author.objects.annotate(
         combined_ages=Sum('age') + Sum('friends__age')).order_by('name')
     for qs in (authors, authors2):
         self.assertQuerysetEqual(qs, [('Adrian Holovaty', 132),
                                       ('Brad Dayley', None),
                                       ('Jacob Kaplan-Moss', 129),
                                       ('James Bennett', 63),
                                       ('Jeffrey Forcier', 128),
                                       ('Paul Bissex', 120),
                                       ('Peter Norvig', 103),
                                       ('Stuart Russell', 103),
                                       ('Wesley J. Chun', 176)], lambda a:
                                  (a.name, a.combined_ages))
示例#10
0
    def test_annotate_defer(self):
        qs = Book.objects.annotate(page_sum=Sum("pages")).defer('name').filter(
            pk=self.b1.pk)

        rows = [(self.b1.id, "159059725", 447,
                 "The Definitive Guide to Django: Web Development Done Right")]
        self.assertQuerysetEqual(qs.order_by('pk'), rows, lambda r:
                                 (r.id, r.isbn, r.page_sum, r.name))
示例#11
0
    def test_related_aggregate(self):
        vals = Author.objects.aggregate(Avg("friends__age"))
        self.assertEqual(vals,
                         {'friends__age__avg': Approximate(34.07, places=2)})

        vals = Book.objects.filter(rating__lt=4.5).aggregate(
            Avg("authors__age"))
        self.assertEqual(vals,
                         {'authors__age__avg': Approximate(38.2857, places=2)})

        vals = Author.objects.all().filter(name__contains="a").aggregate(
            Avg("book__rating"))
        self.assertEqual(vals, {'book__rating__avg': 4.0})

        vals = Book.objects.aggregate(Sum("publisher__num_awards"))
        self.assertEqual(vals, {'publisher__num_awards__sum': 30})

        vals = Publisher.objects.aggregate(Sum("book__price"))
        self.assertEqual(vals, {'book__price__sum': Decimal('270.27')})
示例#12
0
    def test_reverse_fkey_annotate(self):
        books = Book.objects.annotate(
            Sum("publisher__num_awards")).order_by("name")
        self.assertQuerysetEqual(
            books,
            [('Artificial Intelligence: A Modern Approach', 7),
             ('Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp',
              9), ('Practical Django Projects', 3),
             ('Python Web Development with Django', 7),
             ('Sams Teach Yourself Django in 24 Hours', 1),
             ('The Definitive Guide to Django: Web Development Done Right', 3)
             ], lambda b: (b.name, b.publisher__num_awards__sum))

        publishers = Publisher.objects.annotate(
            Sum("book__price")).order_by("name")
        self.assertQuerysetEqual(publishers,
                                 [('Apress', Decimal("59.69")),
                                  ("Jonno's House of Books", None),
                                  ('Morgan Kaufmann', Decimal("75.00")),
                                  ('Prentice Hall', Decimal("112.49")),
                                  ('Sams', Decimal("23.09"))], lambda p:
                                 (p.name, p.book__price__sum))
示例#13
0
    def test_sum_distinct_aggregate(self):
        """
        Sum on a distinct() QuerySet should aggregate only the distinct items.
        """
        authors = Author.objects.filter(book__in=[self.b5, self.b6])
        self.assertEqual(authors.count(), 3)

        distinct_authors = authors.distinct()
        self.assertEqual(distinct_authors.count(), 2)

        # Selected author ages are 57 and 46
        age_sum = distinct_authors.aggregate(Sum('age'))
        self.assertEqual(age_sum['age__sum'], 103)
示例#14
0
 def test_area_with_regular_aggregate(self):
     # Create projected country objects, for this test to work on all backends.
     for c in Country.objects.all():
         CountryWebMercator.objects.create(name=c.name, mpoly=c.mpoly.transform(3857, clone=True))
     # Test in projected coordinate system
     qs = CountryWebMercator.objects.annotate(area_sum=Sum(functions.Area('mpoly')))
     # Some backends (e.g. Oracle) cannot group by multipolygon values, so
     # defer such fields in the aggregation query.
     for c in qs.defer('mpoly'):
         result = c.area_sum
         # If the result is a measure object, get value.
         if isinstance(result, Area):
             result = result.sq_m
         self.assertAlmostEqual((result - c.mpoly.area) / c.mpoly.area, 0)
示例#15
0
    def test_values_annotation_with_expression(self):
        # ensure the F() is promoted to the group by clause
        qs = Author.objects.values('name').annotate(another_age=Sum('age') +
                                                    F('age'))
        a = qs.get(name="Adrian Holovaty")
        self.assertEqual(a['another_age'], 68)

        qs = qs.annotate(friend_count=Count('friends'))
        a = qs.get(name="Adrian Holovaty")
        self.assertEqual(a['friend_count'], 2)

        qs = qs.annotate(combined_age=Sum('age') + F('friends__age')).filter(
            name="Adrian Holovaty").order_by('-combined_age')
        self.assertEqual(list(qs), [{
            "name": 'Adrian Holovaty',
            "another_age": 68,
            "friend_count": 1,
            "combined_age": 69
        }, {
            "name": 'Adrian Holovaty',
            "another_age": 68,
            "friend_count": 1,
            "combined_age": 63
        }])

        vals = qs.values('name', 'combined_age')
        self.assertEqual(list(vals), [
            {
                'name': 'Adrian Holovaty',
                'combined_age': 69
            },
            {
                'name': 'Adrian Holovaty',
                'combined_age': 63
            },
        ])
示例#16
0
    def test_annotated_aggregate_over_annotated_aggregate(self):
        with self.assertRaisesMessage(
                FieldError,
                "Cannot compute Sum('id__max'): 'id__max' is an aggregate"):
            Book.objects.annotate(Max('id')).annotate(Sum('id__max'))

        class MyMax(Max):
            def as_sql(self, compiler, connection):
                self.set_source_expressions(self.get_source_expressions()[0:1])
                return super().as_sql(compiler, connection)

        with self.assertRaisesMessage(
                FieldError,
                "Cannot compute Max('id__max'): 'id__max' is an aggregate"):
            Book.objects.annotate(
                Max('id')).annotate(my_max=MyMax('id__max', 'price'))
示例#17
0
    def test_decimal_max_digits_has_no_effect(self):
        Book.objects.all().delete()
        a1 = Author.objects.first()
        p1 = Publisher.objects.first()
        thedate = timezone.now()
        for i in range(10):
            Book.objects.create(isbn="abcde{}".format(i),
                                name="none",
                                pages=10,
                                rating=4.0,
                                price=9999.98,
                                contact=a1,
                                publisher=p1,
                                pubdate=thedate)

        book = Book.objects.aggregate(price_sum=Sum('price'))
        self.assertEqual(book['price_sum'], Decimal("99999.80"))
示例#18
0
    def test_combine_different_types(self):
        msg = 'Expression contains mixed types. You must set output_field.'
        qs = Book.objects.annotate(sums=Sum('rating') + Sum('pages') +
                                   Sum('price'))
        with self.assertRaisesMessage(FieldError, msg):
            qs.first()
        with self.assertRaisesMessage(FieldError, msg):
            qs.first()

        b1 = Book.objects.annotate(sums=Sum(
            F('rating') + F('pages') +
            F('price'), output_field=IntegerField())).get(pk=self.b4.pk)
        self.assertEqual(b1.sums, 383)

        b2 = Book.objects.annotate(sums=Sum(
            F('rating') + F('pages') +
            F('price'), output_field=FloatField())).get(pk=self.b4.pk)
        self.assertEqual(b2.sums, 383.69)

        b3 = Book.objects.annotate(sums=Sum(
            F('rating') + F('pages') +
            F('price'), output_field=DecimalField())).get(pk=self.b4.pk)
        self.assertEqual(b3.sums, Approximate(Decimal("383.69"), places=2))
示例#19
0
 def test_double_filtered_aggregates(self):
     agg = Sum('age', filter=Q(Q(name='test2') & ~Q(name='test')))
     self.assertEqual(Author.objects.aggregate(age=agg)['age'], 60)
示例#20
0
 def test_values_with_pk_annotation(self):
     # annotate references a field in values() with pk
     publishers = Publisher.objects.values(
         'id', 'book__rating').annotate(total=Sum('book__rating'))
     for publisher in publishers.filter(pk=self.p1.pk):
         self.assertEqual(publisher['book__rating'], publisher['total'])
示例#21
0
 def test_filter_wrong_annotation(self):
     with self.assertRaisesMessage(
             FieldError, "Cannot resolve keyword 'nope' into field."):
         list(
             Book.objects.annotate(sum_rating=Sum('rating')).filter(
                 sum_rating=F('nope')))
示例#22
0
 def test_filter_agg_with_double_f(self):
     books = Book.objects.annotate(sum_rating=Sum('rating')).filter(
         sum_rating=F('sum_rating'))
     for book in books:
         self.assertEqual(book.sum_rating, book.rating)
示例#23
0
 def test_aggregate_over_annotation(self):
     agg = Author.objects.annotate(other_age=F('age')).aggregate(
         otherage_sum=Sum('other_age'))
     other_agg = Author.objects.aggregate(age_sum=Sum('age'))
     self.assertEqual(agg['otherage_sum'], other_agg['age_sum'])
示例#24
0
 def test_case_aggregate(self):
     agg = Sum(
         Case(When(friends__age=40, then=F('friends__age'))),
         filter=Q(friends__name__startswith='test'),
     )
     self.assertEqual(Author.objects.aggregate(age=agg)['age'], 80)
示例#25
0
 def test_filtered_aggregate_on_annotate(self):
     pages_annotate = Sum('book__pages', filter=Q(book__rating__gt=3))
     age_agg = Sum('age', filter=Q(total_pages__gte=400))
     aggregated = Author.objects.annotate(
         total_pages=pages_annotate).aggregate(summed_age=age_agg)
     self.assertEqual(aggregated, {'summed_age': 140})
示例#26
0
 def test_plain_annotate(self):
     agg = Sum('book__pages', filter=Q(book__rating__gt=3))
     qs = Author.objects.annotate(pages=agg).order_by('pk')
     self.assertSequenceEqual([a.pages for a in qs], [447, None, 1047])
示例#27
0
 def test_sum_duration_field(self):
     self.assertEqual(
         Publisher.objects.aggregate(
             Sum('duration', output_field=DurationField())),
         {'duration__sum': datetime.timedelta(days=3)})
示例#28
0
 def test_related_aggregates_m2m(self):
     agg = Sum('friends__age', filter=~Q(friends__name='test'))
     self.assertEqual(
         Author.objects.filter(name='test').aggregate(age=agg)['age'], 160)
示例#29
0
 def test_excluded_aggregates(self):
     agg = Sum('age', filter=~Q(name='test2'))
     self.assertEqual(Author.objects.aggregate(age=agg)['age'], 140)
示例#30
0
 def test_filtered_aggregates(self):
     agg = Sum('age', filter=Q(name__startswith='test'))
     self.assertEqual(Author.objects.aggregate(age=agg)['age'], 200)