Пример #1
0
 def test_transform(self):
     try:
         IntegerField.register_lookup(Chr)
         authors = Author.objects.annotate(name_code_point=Ord('name'))
         self.assertCountEqual(authors.filter(name_code_point__chr=Chr(ord('J'))), [self.john])
         self.assertCountEqual(authors.exclude(name_code_point__chr=Chr(ord('J'))), [self.elena, self.rhonda])
     finally:
         IntegerField._unregister_lookup(Chr)
Пример #2
0
 def test_nonfield_annotation(self):
     book = Book.objects.annotate(
         val=Max(Value(2, output_field=IntegerField()))).first()
     self.assertEqual(book.val, 2)
     book = Book.objects.annotate(
         val=Max(Value(2), output_field=IntegerField())).first()
     self.assertEqual(book.val, 2)
     book = Book.objects.annotate(
         val=Max(2, output_field=IntegerField())).first()
     self.assertEqual(book.val, 2)
Пример #3
0
 def test_union_with_two_annotated_values_list(self):
     qs1 = Number.objects.filter(num=1).annotate(
         count=Value(0, IntegerField()),
     ).values_list('num', 'count')
     qs2 = Number.objects.filter(num=2).values('pk').annotate(
         count=F('num'),
     ).annotate(
         num=Value(1, IntegerField()),
     ).values_list('num', 'count')
     self.assertCountEqual(qs1.union(qs2), [(1, 0), (2, 1)])
Пример #4
0
    def test_add_implementation(self):
        class MySum(Sum):
            pass

        # test completely changing how the output is rendered
        def lower_case_function_override(self, compiler, connection):
            sql, params = compiler.compile(self.source_expressions[0])
            substitutions = {
                'function': self.function.lower(),
                'expressions': sql
            }
            substitutions.update(self.extra)
            return self.template % substitutions, params

        setattr(MySum, 'as_' + connection.vendor, lower_case_function_override)

        qs = Book.objects.annotate(sums=MySum(F('rating') + F('pages') +
                                              F('price'),
                                              output_field=IntegerField()))
        self.assertEqual(str(qs.query).count('sum('), 1)
        b1 = qs.get(pk=self.b4.pk)
        self.assertEqual(b1.sums, 383)

        # test changing the dict and delegating
        def lower_case_function_super(self, compiler, connection):
            self.extra['function'] = self.function.lower()
            return super(MySum, self).as_sql(compiler, connection)

        setattr(MySum, 'as_' + connection.vendor, lower_case_function_super)

        qs = Book.objects.annotate(sums=MySum(F('rating') + F('pages') +
                                              F('price'),
                                              output_field=IntegerField()))
        self.assertEqual(str(qs.query).count('sum('), 1)
        b1 = qs.get(pk=self.b4.pk)
        self.assertEqual(b1.sums, 383)

        # test overriding all parts of the template
        def be_evil(self, compiler, connection):
            substitutions = {'function': 'MAX', 'expressions': '2'}
            substitutions.update(self.extra)
            return self.template % substitutions, ()

        setattr(MySum, 'as_' + connection.vendor, be_evil)

        qs = Book.objects.annotate(sums=MySum(F('rating') + F('pages') +
                                              F('price'),
                                              output_field=IntegerField()))
        self.assertEqual(str(qs.query).count('MAX('), 1)
        b1 = qs.get(pk=self.b4.pk)
        self.assertEqual(b1.sums, 2)
Пример #5
0
 def test_annotate_with_aggregation(self):
     books = Book.objects.annotate(is_book=Value(
         1, output_field=IntegerField()),
                                   rating_count=Count('rating'))
     for book in books:
         self.assertEqual(book.is_book, 1)
         self.assertEqual(book.rating_count, 1)
Пример #6
0
 def test_null_annotation(self):
     """
     Annotating None onto a model round-trips
     """
     book = Book.objects.annotate(
         no_value=Value(None, output_field=IntegerField())).first()
     self.assertIsNone(book.no_value)
Пример #7
0
    def test_column_field_ordering_with_deferred(self):
        store = Store.objects.first()
        Employee.objects.create(id=1,
                                first_name='Max',
                                manager=True,
                                last_name='Paine',
                                store=store,
                                age=23,
                                salary=Decimal(50000.00))
        Employee.objects.create(id=2,
                                first_name='Buffy',
                                manager=False,
                                last_name='Summers',
                                store=store,
                                age=18,
                                salary=Decimal(40000.00))

        qs = Employee.objects.extra(select={
            'random_value': '42'
        }).select_related('store').annotate(
            annotated_value=Value(17, output_field=IntegerField()))

        rows = [(1, 'Max', True, 42, 'Paine', 23, Decimal(50000.00),
                 store.name, 17),
                (2, 'Buffy', False, 42, 'Summers', 18, Decimal(40000.00),
                 store.name, 17)]

        # and we respect deferred columns!
        self.assertQuerysetEqual(
            qs.defer('age').order_by('id'), rows, lambda e:
            (e.id, e.first_name, e.manager, e.random_value, e.last_name, e.age,
             e.salary, e.store.name, e.annotated_value))
Пример #8
0
 def test_mixed_type_annotation_numbers(self):
     test = self.b1
     b = Book.objects.annotate(combined=ExpressionWrapper(
         F('pages') +
         F('rating'), output_field=IntegerField())).get(isbn=test.isbn)
     combined = int(test.pages + test.rating)
     self.assertEqual(b.combined, combined)
Пример #9
0
class Ntile(Func):
    function = 'NTILE'
    output_field = IntegerField()
    window_compatible = True

    def __init__(self, num_buckets=1, **extra):
        if num_buckets <= 0:
            raise ValueError('num_buckets must be greater than 0.')
        super().__init__(num_buckets, **extra)
Пример #10
0
class Extract(TimezoneMixin, Transform):
    lookup_name = None
    output_field = IntegerField()

    def __init__(self, expression, lookup_name=None, tzinfo=None, **extra):
        if self.lookup_name is None:
            self.lookup_name = lookup_name
        if self.lookup_name is None:
            raise ValueError('lookup_name must be provided')
        self.tzinfo = tzinfo
        super().__init__(expression, **extra)

    def as_sql(self, compiler, connection):
        sql, params = compiler.compile(self.lhs)
        lhs_output_field = self.lhs.output_field
        if isinstance(lhs_output_field, DateTimeField):
            tzname = self.get_tzname()
            sql = connection.ops.datetime_extract_sql(self.lookup_name, sql,
                                                      tzname)
        elif isinstance(lhs_output_field, DateField):
            sql = connection.ops.date_extract_sql(self.lookup_name, sql)
        elif isinstance(lhs_output_field, TimeField):
            sql = connection.ops.time_extract_sql(self.lookup_name, sql)
        elif isinstance(lhs_output_field, DurationField):
            if not connection.features.has_native_duration_field:
                raise ValueError(
                    'Extract requires native DurationField database support.')
            sql = connection.ops.time_extract_sql(self.lookup_name, sql)
        else:
            # resolve_expression has already validated the output_field so this
            # assert should never be hit.
            assert False, "Tried to Extract from an invalid type."
        return sql, params

    def resolve_expression(self,
                           query=None,
                           allow_joins=True,
                           reuse=None,
                           summarize=False,
                           for_save=False):
        copy = super().resolve_expression(query, allow_joins, reuse, summarize,
                                          for_save)
        field = copy.lhs.output_field
        if not isinstance(
                field, (DateField, DateTimeField, TimeField, DurationField)):
            raise ValueError(
                'Extract input expression must be DateField, DateTimeField, '
                'TimeField, or DurationField.')
        # Passing dates to functions expecting datetimes is most likely a mistake.
        if type(field) == DateField and copy.lookup_name in ('hour', 'minute',
                                                             'second'):
            raise ValueError(
                "Cannot extract time component '%s' from DateField '%s'. " %
                (copy.lookup_name, field.name))
        return copy
Пример #11
0
class ArrayLenTransform(Transform):
    lookup_name = 'len'
    output_field = IntegerField()

    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        # Distinguish NULL and empty arrays
        return ('CASE WHEN %(lhs)s IS NULL THEN NULL ELSE '
                'coalesce(array_length(%(lhs)s, 1), 0) END') % {
                    'lhs': lhs
                }, params
Пример #12
0
 def test_annotation_filter_with_subquery(self):
     long_books_qs = Book.objects.filter(
         publisher=OuterRef('pk'),
         pages__gt=400,
     ).values('publisher').annotate(count=Count('pk')).values('count')
     publisher_books_qs = Publisher.objects.annotate(
         total_books=Count('book'), ).filter(total_books=Subquery(
             long_books_qs, output_field=IntegerField()), ).values('name')
     self.assertCountEqual(publisher_books_qs, [{
         'name': 'Sams'
     }, {
         'name': 'Morgan Kaufmann'
     }])
Пример #13
0
class Ord(Transform):
    function = 'ASCII'
    lookup_name = 'ord'
    output_field = IntegerField()

    def as_mysql(self, compiler, connection, **extra_context):
        return super().as_sql(compiler,
                              connection,
                              function='ORD',
                              **extra_context)

    def as_sqlite(self, compiler, connection, **extra_context):
        return super().as_sql(compiler,
                              connection,
                              function='UNICODE',
                              **extra_context)
Пример #14
0
 def test_order_raises_on_non_selected_column(self):
     qs1 = Number.objects.filter().annotate(
         annotation=Value(1, IntegerField()),
     ).values('annotation', num2=F('num'))
     qs2 = Number.objects.filter().values('id', 'num')
     # Should not raise
     list(qs1.union(qs2).order_by('annotation'))
     list(qs1.union(qs2).order_by('num2'))
     msg = 'ORDER BY term does not match any column in the result set'
     # 'id' is not part of the select
     with self.assertRaisesMessage(DatabaseError, msg):
         list(qs1.union(qs2).order_by('id'))
     # 'num' got realiased to num2
     with self.assertRaisesMessage(DatabaseError, msg):
         list(qs1.union(qs2).order_by('num'))
     # switched order, now 'exists' again:
     list(qs2.union(qs1).order_by('num'))
Пример #15
0
    def test_column_field_ordering(self):
        """
        Columns are aligned in the correct order for resolve_columns. This test
        will fail on MySQL if column ordering is out. Column fields should be
        aligned as:
        1. extra_select
        2. model_fields
        3. annotation_fields
        4. model_related_fields
        """
        store = Store.objects.first()
        Employee.objects.create(id=1,
                                first_name='Max',
                                manager=True,
                                last_name='Paine',
                                store=store,
                                age=23,
                                salary=Decimal(50000.00))
        Employee.objects.create(id=2,
                                first_name='Buffy',
                                manager=False,
                                last_name='Summers',
                                store=store,
                                age=18,
                                salary=Decimal(40000.00))

        qs = Employee.objects.extra(select={
            'random_value': '42'
        }).select_related('store').annotate(
            annotated_value=Value(17, output_field=IntegerField()))

        rows = [(1, 'Max', True, 42, 'Paine', 23, Decimal(50000.00),
                 store.name, 17),
                (2, 'Buffy', False, 42, 'Summers', 18, Decimal(40000.00),
                 store.name, 17)]

        self.assertQuerysetEqual(
            qs.order_by('id'), rows, lambda e:
            (e.id, e.first_name, e.manager, e.random_value, e.last_name, e.age,
             e.salary, e.store.name, e.annotated_value))
Пример #16
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))
Пример #17
0
 def test_filter_annotation(self):
     books = Book.objects.annotate(
         is_book=Value(1, output_field=IntegerField())).filter(is_book=1)
     for book in books:
         self.assertEqual(book.is_book, 1)
Пример #18
0
class DenseRank(Func):
    function = 'DENSE_RANK'
    output_field = IntegerField()
    window_compatible = True
Пример #19
0
class RowNumber(Func):
    function = 'ROW_NUMBER'
    output_field = IntegerField()
    window_compatible = True
Пример #20
0
class Rank(Func):
    function = 'RANK'
    output_field = IntegerField()
    window_compatible = True
Пример #21
0
class MemSize(GeoFunc):
    output_field = IntegerField()
    arity = 1
Пример #22
0
class NumGeometries(GeoFunc):
    output_field = IntegerField()
    arity = 1
Пример #23
0
class NumPoints(GeoFunc):
    output_field = IntegerField()
    arity = 1
Пример #24
0
class RegrCount(StatAggregate):
    function = 'REGR_COUNT'
    output_field = IntegerField()

    def convert_value(self, value, expression, connection):
        return 0 if value is None else value