diff --git a/django/db/backends/base/features.py b/django/db/backends/base/features.py index c818fb10fe0..ef874d74dbb 100644 --- a/django/db/backends/base/features.py +++ b/django/db/backends/base/features.py @@ -374,6 +374,7 @@ class BaseDatabaseFeatures: "cs": None, # Case-sensitive. "non_default": None, # Non-default. "swedish_ci": None, # Swedish case-insensitive. + "virtual": None, # A collation that can be used for virtual columns. } # SQL template override for tests.aggregation.tests.NowUTC test_now_utc_template = None diff --git a/django/db/backends/mysql/features.py b/django/db/backends/mysql/features.py index 515f4f002c6..637bcbd17c2 100644 --- a/django/db/backends/mysql/features.py +++ b/django/db/backends/mysql/features.py @@ -86,6 +86,7 @@ class DatabaseFeatures(BaseDatabaseFeatures): "ci": f"{charset}_general_ci", "non_default": f"{charset}_esperanto_ci", "swedish_ci": f"{charset}_swedish_ci", + "virtual": f"{charset}_esperanto_ci", } test_now_utc_template = "UTC_TIMESTAMP(6)" diff --git a/django/db/backends/oracle/features.py b/django/db/backends/oracle/features.py index e04dde621db..dfec605c1b4 100644 --- a/django/db/backends/oracle/features.py +++ b/django/db/backends/oracle/features.py @@ -80,12 +80,6 @@ class DatabaseFeatures(BaseDatabaseFeatures): supports_comparing_boolean_expr = False supports_json_field_contains = False supports_collation_on_textfield = False - test_collations = { - "ci": "BINARY_CI", - "cs": "BINARY", - "non_default": "SWEDISH_CI", - "swedish_ci": "SWEDISH_CI", - } test_now_utc_template = "CURRENT_TIMESTAMP AT TIME ZONE 'UTC'" django_test_skips = { @@ -148,6 +142,16 @@ class DatabaseFeatures(BaseDatabaseFeatures): "TimeField": "DateTimeField", } + @cached_property + def test_collations(self): + return { + "ci": "BINARY_CI", + "cs": "BINARY", + "non_default": "SWEDISH_CI", + "swedish_ci": "SWEDISH_CI", + "virtual": "SWEDISH_CI" if self.supports_collation_on_charfield else None, + } + @cached_property def supports_collation_on_charfield(self): with self.connection.cursor() as cursor: diff --git a/django/db/backends/postgresql/features.py b/django/db/backends/postgresql/features.py index 7e6455ae27f..7bcc3564079 100644 --- a/django/db/backends/postgresql/features.py +++ b/django/db/backends/postgresql/features.py @@ -78,6 +78,7 @@ class DatabaseFeatures(BaseDatabaseFeatures): "deterministic": "C", "non_default": "sv-x-icu", "swedish_ci": "sv-x-icu", + "virtual": "sv-x-icu", } test_now_utc_template = "STATEMENT_TIMESTAMP() AT TIME ZONE 'UTC'" insert_test_table_with_defaults = "INSERT INTO {} DEFAULT VALUES" diff --git a/django/db/backends/sqlite3/features.py b/django/db/backends/sqlite3/features.py index 3d66466af50..713d8bd38ff 100644 --- a/django/db/backends/sqlite3/features.py +++ b/django/db/backends/sqlite3/features.py @@ -47,6 +47,7 @@ class DatabaseFeatures(BaseDatabaseFeatures): "ci": "nocase", "cs": "binary", "non_default": "nocase", + "virtual": "nocase", } django_test_expected_failures = { # The django_format_dtdelta() function doesn't properly handle mixed diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py index b966da59e56..7804c198815 100644 --- a/tests/model_fields/models.py +++ b/tests/model_fields/models.py @@ -20,7 +20,7 @@ except ImportError: test_collation = SimpleLazyObject( - lambda: connection.features.test_collations.get("non_default") + lambda: connection.features.test_collations["virtual"] ) @@ -529,10 +529,7 @@ class GeneratedModelOutputField(models.Model): ) class Meta: - required_db_features = { - "supports_stored_generated_columns", - "supports_collation_on_charfield", - } + required_db_features = {"supports_stored_generated_columns"} class GeneratedModelOutputFieldVirtual(models.Model): @@ -544,10 +541,7 @@ class GeneratedModelOutputFieldVirtual(models.Model): ) class Meta: - required_db_features = { - "supports_virtual_generated_columns", - "supports_collation_on_charfield", - } + required_db_features = {"supports_virtual_generated_columns"} class GeneratedModelNull(models.Model): diff --git a/tests/model_fields/test_generatedfield.py b/tests/model_fields/test_generatedfield.py index d965940465f..a37e3749813 100644 --- a/tests/model_fields/test_generatedfield.py +++ b/tests/model_fields/test_generatedfield.py @@ -165,12 +165,8 @@ class GeneratedFieldTestMixin: with self.assertNumQueries(0), self.assertRaises(does_not_exist): self.base_model.objects.get(field__gte=overflow_value) - @skipUnlessDBFeature("supports_collation_on_charfield") def test_output_field(self): - collation = connection.features.test_collations.get("non_default") - if not collation: - self.skipTest("Language collations are not supported.") - + collation = connection.features.test_collations["virtual"] m = self.output_field_model.objects.create(name="NAME") field = m._meta.get_field("lower_name") db_parameters = field.db_parameters(connection) @@ -181,7 +177,6 @@ class GeneratedFieldTestMixin: field._resolved_expression.output_field.db_type(connection), ) - @skipUnlessDBFeature("supports_collation_on_charfield") def test_db_type_parameters(self): db_type_parameters = self.output_field_model._meta.get_field( "lower_name"