diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index 855e8cc28d24..c4a730f47bcb 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -1828,9 +1828,8 @@ def to_python(self, value): ) return decimal_value - def get_db_prep_save(self, value, connection): - if hasattr(value, "as_sql"): - return value + def get_db_prep_value(self, value, connection, prepared=False): + value = super().get_db_prep_value(value, connection, prepared) return connection.ops.adapt_decimalfield_value( self.to_python(value), self.max_digits, self.decimal_places ) diff --git a/tests/model_fields/test_decimalfield.py b/tests/model_fields/test_decimalfield.py index 588bb64a3a12..17f59674e872 100644 --- a/tests/model_fields/test_decimalfield.py +++ b/tests/model_fields/test_decimalfield.py @@ -1,9 +1,10 @@ import math from decimal import Decimal +from unittest import mock from django.core import validators from django.core.exceptions import ValidationError -from django.db import models +from django.db import connection, models from django.test import TestCase from .models import BigD, Foo @@ -48,6 +49,20 @@ def test_get_prep_value(self): self.assertIsNone(f.get_prep_value(None)) self.assertEqual(f.get_prep_value("2.4"), Decimal("2.4")) + def test_get_db_prep_value(self): + """ + DecimalField.get_db_prep_value() must call + DatabaseOperations.adapt_decimalfield_value(). + """ + f = models.DecimalField(max_digits=5, decimal_places=1) + # None of the built-in database backends implement + # adapt_decimalfield_value(), so this must be confirmed with mocking. + with mock.patch.object( + connection.ops.__class__, "adapt_decimalfield_value" + ) as adapt_decimalfield_value: + f.get_db_prep_value("2.4", connection) + adapt_decimalfield_value.assert_called_with(Decimal("2.4"), 5, 1) + def test_filter_with_strings(self): """ Should be able to filter decimal fields using strings (#8023).