mirror of
https://github.com/django/django.git
synced 2024-12-23 01:25:58 +00:00
Refs #23941 -- Prevented incorrect rounding of DecimalField annotations on SQLite.
This commit is contained in:
parent
ad9390bba2
commit
ebc4ee3369
@ -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):
|
||||||
|
@ -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),))
|
||||||
|
Loading…
Reference in New Issue
Block a user