2
0
Эх сурвалжийг харах

Fixed #34547 -- Deprecated DatabaseOperations.field_cast_sql().

David Smith 1 жил өмнө
parent
commit
27b399d235

+ 9 - 0
django/db/backends/base/operations.py

@@ -1,6 +1,7 @@
 import datetime
 import datetime
 import decimal
 import decimal
 import json
 import json
+import warnings
 from importlib import import_module
 from importlib import import_module
 
 
 import sqlparse
 import sqlparse
@@ -10,6 +11,7 @@ from django.db import NotSupportedError, transaction
 from django.db.backends import utils
 from django.db.backends import utils
 from django.db.models.expressions import Col
 from django.db.models.expressions import Col
 from django.utils import timezone
 from django.utils import timezone
+from django.utils.deprecation import RemovedInDjango60Warning
 from django.utils.encoding import force_str
 from django.utils.encoding import force_str
 
 
 
 
@@ -220,6 +222,13 @@ class BaseDatabaseOperations:
         it in a WHERE statement. The resulting string should contain a '%s'
         it in a WHERE statement. The resulting string should contain a '%s'
         placeholder for the column being searched against.
         placeholder for the column being searched against.
         """
         """
+        warnings.warn(
+            (
+                "DatabaseOperations.field_cast_sql() is deprecated use "
+                "DatabaseOperations.lookup_cast() instead."
+            ),
+            RemovedInDjango60Warning,
+        )
         return "%s"
         return "%s"
 
 
     def force_no_ordering(self):
     def force_no_ordering(self):

+ 19 - 2
django/db/models/lookups.py

@@ -1,7 +1,9 @@
 import itertools
 import itertools
 import math
 import math
+import warnings
 
 
 from django.core.exceptions import EmptyResultSet, FullResultSet
 from django.core.exceptions import EmptyResultSet, FullResultSet
+from django.db.backends.base.operations import BaseDatabaseOperations
 from django.db.models.expressions import Case, Expression, Func, Value, When
 from django.db.models.expressions import Case, Expression, Func, Value, When
 from django.db.models.fields import (
 from django.db.models.fields import (
     BooleanField,
     BooleanField,
@@ -13,6 +15,7 @@ from django.db.models.fields import (
 )
 )
 from django.db.models.query_utils import RegisterLookupMixin
 from django.db.models.query_utils import RegisterLookupMixin
 from django.utils.datastructures import OrderedSet
 from django.utils.datastructures import OrderedSet
+from django.utils.deprecation import RemovedInDjango60Warning
 from django.utils.functional import cached_property
 from django.utils.functional import cached_property
 from django.utils.hashable import make_hashable
 from django.utils.hashable import make_hashable
 
 
@@ -217,8 +220,22 @@ class BuiltinLookup(Lookup):
     def process_lhs(self, compiler, connection, lhs=None):
     def process_lhs(self, compiler, connection, lhs=None):
         lhs_sql, params = super().process_lhs(compiler, connection, lhs)
         lhs_sql, params = super().process_lhs(compiler, connection, lhs)
         field_internal_type = self.lhs.output_field.get_internal_type()
         field_internal_type = self.lhs.output_field.get_internal_type()
-        db_type = self.lhs.output_field.db_type(connection=connection)
-        lhs_sql = connection.ops.field_cast_sql(db_type, field_internal_type) % lhs_sql
+        if (
+            hasattr(connection.ops.__class__, "field_cast_sql")
+            and connection.ops.__class__.field_cast_sql
+            is not BaseDatabaseOperations.field_cast_sql
+        ):
+            warnings.warn(
+                (
+                    "The usage of DatabaseOperations.field_cast_sql() is deprecated. "
+                    "Implement DatabaseOperations.lookup_cast() instead."
+                ),
+                RemovedInDjango60Warning,
+            )
+            db_type = self.lhs.output_field.db_type(connection=connection)
+            lhs_sql = (
+                connection.ops.field_cast_sql(db_type, field_internal_type) % lhs_sql
+            )
         lhs_sql = (
         lhs_sql = (
             connection.ops.lookup_cast(self.lookup_name, field_internal_type) % lhs_sql
             connection.ops.lookup_cast(self.lookup_name, field_internal_type) % lhs_sql
         )
         )

+ 2 - 0
docs/internals/deprecation.txt

@@ -40,6 +40,8 @@ details on these changes.
 
 
 * Support for ``cx_Oracle`` will be removed.
 * Support for ``cx_Oracle`` will be removed.
 
 
+* ``BaseDatabaseOperations.field_cast_sql()`` will be removed.
+
 .. _deprecation-removed-in-5.1:
 .. _deprecation-removed-in-5.1:
 
 
 5.1
 5.1

+ 5 - 0
docs/releases/5.0.txt

@@ -663,6 +663,11 @@ Miscellaneous
 * Support for ``cx_Oracle`` is deprecated in favor of `oracledb`_ 1.3.2+ Python
 * Support for ``cx_Oracle`` is deprecated in favor of `oracledb`_ 1.3.2+ Python
   driver.
   driver.
 
 
+* ``DatabaseOperations.field_cast_sql()`` is deprecated in favor of
+  ``DatabaseOperations.lookup_cast()``. Starting with Django 6.0,
+  ``BuiltinLookup.process_lhs()`` will no longer call ``field_cast_sql()``.
+  Third-party database backends should implement ``lookup_cast()`` instead.
+
 .. _`oracledb`: https://oracle.github.io/python-oracledb/
 .. _`oracledb`: https://oracle.github.io/python-oracledb/
 
 
 Features removed in 5.0
 Features removed in 5.0

+ 24 - 0
tests/backends/base/test_operations.py

@@ -1,10 +1,12 @@
 import decimal
 import decimal
+from unittest import mock
 
 
 from django.core.management.color import no_style
 from django.core.management.color import no_style
 from django.db import NotSupportedError, connection, transaction
 from django.db import NotSupportedError, connection, transaction
 from django.db.backends.base.operations import BaseDatabaseOperations
 from django.db.backends.base.operations import BaseDatabaseOperations
 from django.db.models import DurationField, Value
 from django.db.models import DurationField, Value
 from django.db.models.expressions import Col
 from django.db.models.expressions import Col
+from django.db.models.lookups import Exact
 from django.test import (
 from django.test import (
     SimpleTestCase,
     SimpleTestCase,
     TestCase,
     TestCase,
@@ -13,6 +15,7 @@ from django.test import (
     skipIfDBFeature,
     skipIfDBFeature,
 )
 )
 from django.utils import timezone
 from django.utils import timezone
+from django.utils.deprecation import RemovedInDjango60Warning
 
 
 from ..models import Author, Book
 from ..models import Author, Book
 
 
@@ -235,3 +238,24 @@ class SqlFlushTests(TransactionTestCase):
                 self.assertEqual(author.pk, 1)
                 self.assertEqual(author.pk, 1)
                 book = Book.objects.create(author=author)
                 book = Book.objects.create(author=author)
                 self.assertEqual(book.pk, 1)
                 self.assertEqual(book.pk, 1)
+
+
+class DeprecationTests(TestCase):
+    def test_field_cast_sql_warning(self):
+        base_ops = BaseDatabaseOperations(connection=connection)
+        msg = (
+            "DatabaseOperations.field_cast_sql() is deprecated use "
+            "DatabaseOperations.lookup_cast() instead."
+        )
+        with self.assertRaisesMessage(RemovedInDjango60Warning, msg):
+            base_ops.field_cast_sql("integer", "IntegerField")
+
+    def test_field_cast_sql_usage_warning(self):
+        compiler = Author.objects.all().query.get_compiler(connection.alias)
+        msg = (
+            "The usage of DatabaseOperations.field_cast_sql() is deprecated. Implement "
+            "DatabaseOperations.lookup_cast() instead."
+        )
+        with mock.patch.object(connection.ops.__class__, "field_cast_sql"):
+            with self.assertRaisesMessage(RemovedInDjango60Warning, msg):
+                Exact("name", "book__author__name").as_sql(compiler, connection)