1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Refs #23941 -- Prevented incorrect rounding of DecimalField annotations on SQLite.

This commit is contained in:
Sergey Fedoseev 2017-12-22 05:50:56 +05:00 committed by Tim Graham
parent ad9390bba2
commit ebc4ee3369
2 changed files with 21 additions and 2 deletions

View File

@ -1,12 +1,13 @@
import datetime import datetime
import decimal
import uuid import uuid
from decimal import Decimal
from django.conf import settings from django.conf import settings
from django.core.exceptions import FieldError from django.core.exceptions import FieldError
from django.db import utils from django.db import utils
from django.db.backends.base.operations import BaseDatabaseOperations from django.db.backends.base.operations import BaseDatabaseOperations
from django.db.models import aggregates, fields from django.db.models import aggregates, fields
from django.db.models.expressions import Col
from django.utils import timezone from django.utils import timezone
from django.utils.dateparse import parse_date, parse_datetime, parse_time from django.utils.dateparse import parse_date, parse_datetime, parse_time
from django.utils.duration import duration_string from django.utils.duration import duration_string
@ -242,8 +243,12 @@ class DatabaseOperations(BaseDatabaseOperations):
def convert_decimalfield_value(self, value, expression, connection): def convert_decimalfield_value(self, value, expression, connection):
if value is not None: if value is not None:
if not isinstance(expression, Col):
# SQLite stores only 15 significant digits. Digits coming from
# float inaccuracy must be removed.
return decimal.Context(prec=15).create_decimal_from_float(value)
value = expression.output_field.format_number(value) value = expression.output_field.format_number(value)
value = Decimal(value) return decimal.Decimal(value)
return value return value
def convert_uuidfield_value(self, value, expression, connection): def convert_uuidfield_value(self, value, expression, connection):

View File

@ -244,6 +244,20 @@ class NonAggregateAnnotationTestCase(TestCase):
sum_rating=Sum('rating') sum_rating=Sum('rating')
).filter(sum_rating=F('nope'))) ).filter(sum_rating=F('nope')))
def test_decimal_annotation(self):
salary = Decimal(10) ** -Employee._meta.get_field('salary').decimal_places
Employee.objects.create(
first_name='Max',
last_name='Paine',
store=Store.objects.first(),
age=23,
salary=salary,
)
self.assertEqual(
Employee.objects.annotate(new_salary=F('salary') / 10).get().new_salary,
salary / 10,
)
def test_filter_decimal_annotation(self): def test_filter_decimal_annotation(self):
qs = Book.objects.annotate(new_price=F('price') + 1).filter(new_price=Decimal(31)).values_list('new_price') qs = Book.objects.annotate(new_price=F('price') + 1).filter(new_price=Decimal(31)).values_list('new_price')
self.assertEqual(qs.get(), (Decimal(31),)) self.assertEqual(qs.get(), (Decimal(31),))