From 44908d4d9360f72b9511aa0a878458285ba326d4 Mon Sep 17 00:00:00 2001 From: Sergey Fedoseev Date: Thu, 28 Dec 2017 05:16:37 +0500 Subject: [PATCH] Fixed #28967 -- Prevented Cast to FloatField from rounding to integer on MySQL. --- django/db/backends/mysql/operations.py | 1 - django/db/models/functions/comparison.py | 5 +++++ tests/db_functions/test_cast.py | 7 +++++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/django/db/backends/mysql/operations.py b/django/db/backends/mysql/operations.py index 3ec1c2e8ce..7c901d78d8 100644 --- a/django/db/backends/mysql/operations.py +++ b/django/db/backends/mysql/operations.py @@ -20,7 +20,6 @@ class DatabaseOperations(BaseDatabaseOperations): 'IntegerField': 'signed integer', 'BigIntegerField': 'signed integer', 'SmallIntegerField': 'signed integer', - 'FloatField': 'signed', 'PositiveIntegerField': 'unsigned integer', 'PositiveSmallIntegerField': 'unsigned integer', } diff --git a/django/db/models/functions/comparison.py b/django/db/models/functions/comparison.py index dba30979a8..8bf4fdc8d7 100644 --- a/django/db/models/functions/comparison.py +++ b/django/db/models/functions/comparison.py @@ -14,6 +14,11 @@ class Cast(Func): extra_context['db_type'] = self.output_field.cast_db_type(connection) return super().as_sql(compiler, connection, **extra_context) + def as_mysql(self, compiler, connection): + # MySQL doesn't support explicit cast to float. + template = '(%(expressions)s + 0.0)' if self.output_field.get_internal_type() == 'FloatField' else None + return self.as_sql(compiler, connection, template=template) + def as_postgresql(self, compiler, connection): # CAST would be valid too, but the :: shortcut syntax is more readable. return self.as_sql(compiler, connection, template='%(expressions)s::%(db_type)s') diff --git a/tests/db_functions/test_cast.py b/tests/db_functions/test_cast.py index 42bbce118e..36220cf640 100644 --- a/tests/db_functions/test_cast.py +++ b/tests/db_functions/test_cast.py @@ -1,4 +1,5 @@ import datetime +import decimal from django.db import models from django.db.models.expressions import Value @@ -55,5 +56,7 @@ class CastTests(TestCase): self.assertEqual(dates.get().cast_datetime, now) def test_cast_from_python(self): - numbers = Author.objects.annotate(cast_float=Cast(0, models.FloatField())) - self.assertEqual(numbers.get().cast_float, 0.0) + numbers = Author.objects.annotate(cast_float=Cast(decimal.Decimal(0.125), models.FloatField())) + cast_float = numbers.get().cast_float + self.assertIsInstance(cast_float, float) + self.assertEqual(cast_float, 0.125)