[1.11.x] Refs #18247 -- Fixed SQLite QuerySet filtering on decimal result of Least and Greatest.

Backport of 068d75688f from master
This commit is contained in:
Sergey Fedoseev 2017-03-29 22:29:53 +05:00 committed by Tim Graham
parent d476fa96ac
commit 8484cf4cd0
4 changed files with 29 additions and 5 deletions

View File

@ -570,8 +570,8 @@ class Func(Expression):
data['expressions'] = data['field'] = arg_joiner.join(sql_parts) data['expressions'] = data['field'] = arg_joiner.join(sql_parts)
return template % data, params return template % data, params
def as_sqlite(self, compiler, connection): def as_sqlite(self, compiler, connection, **extra_context):
sql, params = self.as_sql(compiler, connection) sql, params = self.as_sql(compiler, connection, **extra_context)
try: try:
if self.output_field.get_internal_type() == 'DecimalField': if self.output_field.get_internal_type() == 'DecimalField':
sql = 'CAST(%s AS NUMERIC)' % sql sql = 'CAST(%s AS NUMERIC)' % sql

View File

@ -137,7 +137,7 @@ class Greatest(Func):
def as_sqlite(self, compiler, connection): def as_sqlite(self, compiler, connection):
"""Use the MAX function on SQLite.""" """Use the MAX function on SQLite."""
return super(Greatest, self).as_sql(compiler, connection, function='MAX') return super(Greatest, self).as_sqlite(compiler, connection, function='MAX')
class Least(Func): class Least(Func):
@ -157,7 +157,7 @@ class Least(Func):
def as_sqlite(self, compiler, connection): def as_sqlite(self, compiler, connection):
"""Use the MIN function on SQLite.""" """Use the MIN function on SQLite."""
return super(Least, self).as_sql(compiler, connection, function='MIN') return super(Least, self).as_sqlite(compiler, connection, function='MIN')
class Length(Transform): class Length(Transform):

View File

@ -56,3 +56,8 @@ class DTModel(models.Model):
def __str__(self): def __str__(self):
return 'DTModel({0})'.format(self.name) return 'DTModel({0})'.format(self.name)
class DecimalModel(models.Model):
n1 = models.DecimalField(decimal_places=2, max_digits=6)
n2 = models.DecimalField(decimal_places=2, max_digits=6)

View File

@ -1,6 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from datetime import datetime, timedelta from datetime import datetime, timedelta
from decimal import Decimal
from unittest import skipIf, skipUnless from unittest import skipIf, skipUnless
from django.db import connection from django.db import connection
@ -13,7 +14,7 @@ from django.db.models.functions import (
from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature from django.test import TestCase, skipIfDBFeature, skipUnlessDBFeature
from django.utils import timezone from django.utils import timezone
from .models import Article, Author, Fan from .models import Article, Author, DecimalModel, Fan
lorem_ipsum = """ lorem_ipsum = """
@ -204,6 +205,15 @@ class FunctionTests(TestCase):
author.refresh_from_db() author.refresh_from_db()
self.assertEqual(author.alias, 'Jim') self.assertEqual(author.alias, 'Jim')
def test_greatest_decimal_filter(self):
obj = DecimalModel.objects.create(n1=Decimal('1.1'), n2=Decimal('1.2'))
self.assertCountEqual(
DecimalModel.objects.annotate(
greatest=Greatest('n1', 'n2'),
).filter(greatest=Decimal('1.2')),
[obj],
)
def test_least(self): def test_least(self):
now = timezone.now() now = timezone.now()
before = now - timedelta(hours=1) before = now - timedelta(hours=1)
@ -299,6 +309,15 @@ class FunctionTests(TestCase):
author.refresh_from_db() author.refresh_from_db()
self.assertEqual(author.alias, 'James Smith') self.assertEqual(author.alias, 'James Smith')
def test_least_decimal_filter(self):
obj = DecimalModel.objects.create(n1=Decimal('1.1'), n2=Decimal('1.2'))
self.assertCountEqual(
DecimalModel.objects.annotate(
least=Least('n1', 'n2'),
).filter(least=Decimal('1.1')),
[obj],
)
def test_concat(self): def test_concat(self):
Author.objects.create(name='Jayden') Author.objects.create(name='Jayden')
Author.objects.create(name='John Smith', alias='smithj', goes_by='John') Author.objects.create(name='John Smith', alias='smithj', goes_by='John')