mirror of
https://github.com/django/django.git
synced 2025-01-03 15:06:09 +00:00
Fixed #35479 -- Dropped support for PostgreSQL 13 and PostGIS 3.0.
This commit is contained in:
parent
bcbc4b9b8a
commit
b049bec7cf
4
.github/workflows/schedule_tests.yml
vendored
4
.github/workflows/schedule_tests.yml
vendored
@ -90,7 +90,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:13-alpine
|
image: postgres:14-alpine
|
||||||
env:
|
env:
|
||||||
POSTGRES_DB: django
|
POSTGRES_DB: django
|
||||||
POSTGRES_USER: user
|
POSTGRES_USER: user
|
||||||
@ -163,7 +163,7 @@ jobs:
|
|||||||
name: Selenium tests, PostgreSQL
|
name: Selenium tests, PostgreSQL
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:13-alpine
|
image: postgres:14-alpine
|
||||||
env:
|
env:
|
||||||
POSTGRES_DB: django
|
POSTGRES_DB: django
|
||||||
POSTGRES_USER: user
|
POSTGRES_USER: user
|
||||||
|
2
.github/workflows/selenium.yml
vendored
2
.github/workflows/selenium.yml
vendored
@ -43,7 +43,7 @@ jobs:
|
|||||||
name: PostgreSQL
|
name: PostgreSQL
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:13-alpine
|
image: postgres:14-alpine
|
||||||
env:
|
env:
|
||||||
POSTGRES_DB: django
|
POSTGRES_DB: django
|
||||||
POSTGRES_USER: user
|
POSTGRES_USER: user
|
||||||
|
@ -203,7 +203,7 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
|
|||||||
raise ImproperlyConfigured(
|
raise ImproperlyConfigured(
|
||||||
'Cannot determine PostGIS version for database "%s" '
|
'Cannot determine PostGIS version for database "%s" '
|
||||||
'using command "SELECT postgis_lib_version()". '
|
'using command "SELECT postgis_lib_version()". '
|
||||||
"GeoDjango requires at least PostGIS version 3.0. "
|
"GeoDjango requires at least PostGIS version 3.1. "
|
||||||
"Was the database created from a spatial database "
|
"Was the database created from a spatial database "
|
||||||
"template?" % self.connection.settings_dict["NAME"]
|
"template?" % self.connection.settings_dict["NAME"]
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from types import NoneType
|
from types import NoneType
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import DEFAULT_DB_ALIAS, NotSupportedError
|
from django.db import DEFAULT_DB_ALIAS
|
||||||
from django.db.backends.ddl_references import Expressions, Statement, Table
|
from django.db.backends.ddl_references import Expressions, Statement, Table
|
||||||
from django.db.models import BaseConstraint, Deferrable, F, Q
|
from django.db.models import BaseConstraint, Deferrable, F, Q
|
||||||
from django.db.models.expressions import Exists, ExpressionList
|
from django.db.models.expressions import Exists, ExpressionList
|
||||||
@ -114,7 +114,6 @@ class ExclusionConstraint(BaseConstraint):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def create_sql(self, model, schema_editor):
|
def create_sql(self, model, schema_editor):
|
||||||
self.check_supported(schema_editor)
|
|
||||||
return Statement(
|
return Statement(
|
||||||
"ALTER TABLE %(table)s ADD %(constraint)s",
|
"ALTER TABLE %(table)s ADD %(constraint)s",
|
||||||
table=Table(model._meta.db_table, schema_editor.quote_name),
|
table=Table(model._meta.db_table, schema_editor.quote_name),
|
||||||
@ -128,17 +127,6 @@ class ExclusionConstraint(BaseConstraint):
|
|||||||
schema_editor.quote_name(self.name),
|
schema_editor.quote_name(self.name),
|
||||||
)
|
)
|
||||||
|
|
||||||
def check_supported(self, schema_editor):
|
|
||||||
if (
|
|
||||||
self.include
|
|
||||||
and self.index_type.lower() == "spgist"
|
|
||||||
and not schema_editor.connection.features.supports_covering_spgist_indexes
|
|
||||||
):
|
|
||||||
raise NotSupportedError(
|
|
||||||
"Covering exclusion constraints using an SP-GiST index "
|
|
||||||
"require PostgreSQL 14+."
|
|
||||||
)
|
|
||||||
|
|
||||||
def deconstruct(self):
|
def deconstruct(self):
|
||||||
path, args, kwargs = super().deconstruct()
|
path, args, kwargs = super().deconstruct()
|
||||||
kwargs["expressions"] = self.expressions
|
kwargs["expressions"] = self.expressions
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
from django.db import NotSupportedError
|
|
||||||
from django.db.models import Func, Index
|
from django.db.models import Func, Index
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
|
|
||||||
@ -234,13 +233,6 @@ class SpGistIndex(PostgresIndex):
|
|||||||
with_params.append("fillfactor = %d" % self.fillfactor)
|
with_params.append("fillfactor = %d" % self.fillfactor)
|
||||||
return with_params
|
return with_params
|
||||||
|
|
||||||
def check_supported(self, schema_editor):
|
|
||||||
if (
|
|
||||||
self.include
|
|
||||||
and not schema_editor.connection.features.supports_covering_spgist_indexes
|
|
||||||
):
|
|
||||||
raise NotSupportedError("Covering SP-GiST indexes require PostgreSQL 14+.")
|
|
||||||
|
|
||||||
|
|
||||||
class OpClass(Func):
|
class OpClass(Func):
|
||||||
template = "%(expressions)s %(name)s"
|
template = "%(expressions)s %(name)s"
|
||||||
|
@ -7,7 +7,7 @@ from django.utils.functional import cached_property
|
|||||||
|
|
||||||
|
|
||||||
class DatabaseFeatures(BaseDatabaseFeatures):
|
class DatabaseFeatures(BaseDatabaseFeatures):
|
||||||
minimum_database_version = (13,)
|
minimum_database_version = (14,)
|
||||||
allows_group_by_selected_pks = True
|
allows_group_by_selected_pks = True
|
||||||
can_return_columns_from_insert = True
|
can_return_columns_from_insert = True
|
||||||
can_return_rows_from_bulk_insert = True
|
can_return_rows_from_bulk_insert = True
|
||||||
@ -152,10 +152,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||||||
"PositiveSmallIntegerField": "SmallIntegerField",
|
"PositiveSmallIntegerField": "SmallIntegerField",
|
||||||
}
|
}
|
||||||
|
|
||||||
@cached_property
|
|
||||||
def is_postgresql_14(self):
|
|
||||||
return self.connection.pg_version >= 140000
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def is_postgresql_15(self):
|
def is_postgresql_15(self):
|
||||||
return self.connection.pg_version >= 150000
|
return self.connection.pg_version >= 150000
|
||||||
@ -164,8 +160,6 @@ class DatabaseFeatures(BaseDatabaseFeatures):
|
|||||||
def is_postgresql_16(self):
|
def is_postgresql_16(self):
|
||||||
return self.connection.pg_version >= 160000
|
return self.connection.pg_version >= 160000
|
||||||
|
|
||||||
has_bit_xor = property(operator.attrgetter("is_postgresql_14"))
|
|
||||||
supports_covering_spgist_indexes = property(operator.attrgetter("is_postgresql_14"))
|
|
||||||
supports_unlimited_charfield = True
|
supports_unlimited_charfield = True
|
||||||
supports_nulls_distinct_unique_constraints = property(
|
supports_nulls_distinct_unique_constraints = property(
|
||||||
operator.attrgetter("is_postgresql_15")
|
operator.attrgetter("is_postgresql_15")
|
||||||
|
@ -12,7 +12,7 @@ Program Description Required
|
|||||||
`PROJ`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 9.x, 8.x, 7.x, 6.x
|
`PROJ`_ Cartographic Projections library Yes (PostgreSQL and SQLite only) 9.x, 8.x, 7.x, 6.x
|
||||||
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 3.8, 3.7, 3.6, 3.5, 3.4, 3.3, 3.2, 3.1, 3.0
|
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 3.8, 3.7, 3.6, 3.5, 3.4, 3.3, 3.2, 3.1, 3.0
|
||||||
:doc:`GeoIP <../geoip2>` IP-based geolocation library No 2
|
:doc:`GeoIP <../geoip2>` IP-based geolocation library No 2
|
||||||
`PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 3.4, 3.3, 3.2, 3.1, 3.0
|
`PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 3.4, 3.3, 3.2, 3.1
|
||||||
`SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 5.1, 5.0, 4.3
|
`SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 5.1, 5.0, 4.3
|
||||||
======================== ==================================== ================================ ===========================================
|
======================== ==================================== ================================ ===========================================
|
||||||
|
|
||||||
@ -35,7 +35,6 @@ totally fine with GeoDjango. Your mileage may vary.
|
|||||||
GDAL 3.6.0 2022-11-03
|
GDAL 3.6.0 2022-11-03
|
||||||
GDAL 3.7.0 2023-05-10
|
GDAL 3.7.0 2023-05-10
|
||||||
GDAL 3.8.0 2023-11-13
|
GDAL 3.8.0 2023-11-13
|
||||||
PostGIS 3.0.0 2019-10-20
|
|
||||||
PostGIS 3.1.0 2020-12-18
|
PostGIS 3.1.0 2020-12-18
|
||||||
PostGIS 3.2.0 2021-12-18
|
PostGIS 3.2.0 2021-12-18
|
||||||
PostGIS 3.3.0 2022-08-27
|
PostGIS 3.3.0 2022-08-27
|
||||||
|
@ -56,7 +56,7 @@ supported versions, and any notes for each of the supported database backends:
|
|||||||
================== ============================== ================== =========================================
|
================== ============================== ================== =========================================
|
||||||
Database Library Requirements Supported Versions Notes
|
Database Library Requirements Supported Versions Notes
|
||||||
================== ============================== ================== =========================================
|
================== ============================== ================== =========================================
|
||||||
PostgreSQL GEOS, GDAL, PROJ, PostGIS 13+ Requires PostGIS.
|
PostgreSQL GEOS, GDAL, PROJ, PostGIS 14+ Requires PostGIS.
|
||||||
MySQL GEOS, GDAL 8.0.11+ :ref:`Limited functionality <mysql-spatial-limitations>`.
|
MySQL GEOS, GDAL 8.0.11+ :ref:`Limited functionality <mysql-spatial-limitations>`.
|
||||||
Oracle GEOS, GDAL 19+ XE not supported.
|
Oracle GEOS, GDAL 19+ XE not supported.
|
||||||
SQLite GEOS, GDAL, PROJ, SpatiaLite 3.31.0+ Requires SpatiaLite 4.3+
|
SQLite GEOS, GDAL, PROJ, SpatiaLite 3.31.0+ Requires SpatiaLite 4.3+
|
||||||
@ -300,7 +300,7 @@ Summary:
|
|||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
$ sudo port install postgresql13-server
|
$ sudo port install postgresql14-server
|
||||||
$ sudo port install geos
|
$ sudo port install geos
|
||||||
$ sudo port install proj6
|
$ sudo port install proj6
|
||||||
$ sudo port install postgis3
|
$ sudo port install postgis3
|
||||||
@ -314,14 +314,14 @@ Summary:
|
|||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
export PATH=/opt/local/bin:/opt/local/lib/postgresql13/bin
|
export PATH=/opt/local/bin:/opt/local/lib/postgresql14/bin
|
||||||
|
|
||||||
In addition, add the ``DYLD_FALLBACK_LIBRARY_PATH`` setting so that
|
In addition, add the ``DYLD_FALLBACK_LIBRARY_PATH`` setting so that
|
||||||
the libraries can be found by Python:
|
the libraries can be found by Python:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
export DYLD_FALLBACK_LIBRARY_PATH=/opt/local/lib:/opt/local/lib/postgresql13
|
export DYLD_FALLBACK_LIBRARY_PATH=/opt/local/lib:/opt/local/lib/postgresql14
|
||||||
|
|
||||||
__ https://www.macports.org/
|
__ https://www.macports.org/
|
||||||
|
|
||||||
|
@ -14,12 +14,6 @@ All of these functions are available from the
|
|||||||
|
|
||||||
Returns a version 4 UUID.
|
Returns a version 4 UUID.
|
||||||
|
|
||||||
On PostgreSQL < 13, the `pgcrypto extension`_ must be installed. You can use
|
|
||||||
the :class:`~django.contrib.postgres.operations.CryptoExtension` migration
|
|
||||||
operation to install it.
|
|
||||||
|
|
||||||
.. _pgcrypto extension: https://www.postgresql.org/docs/current/pgcrypto.html
|
|
||||||
|
|
||||||
Usage example:
|
Usage example:
|
||||||
|
|
||||||
.. code-block:: pycon
|
.. code-block:: pycon
|
||||||
|
@ -115,7 +115,7 @@ below for information on how to set up your database correctly.
|
|||||||
PostgreSQL notes
|
PostgreSQL notes
|
||||||
================
|
================
|
||||||
|
|
||||||
Django supports PostgreSQL 13 and higher. `psycopg`_ 3.1.8+ or `psycopg2`_
|
Django supports PostgreSQL 14 and higher. `psycopg`_ 3.1.8+ or `psycopg2`_
|
||||||
2.8.4+ is required, though the latest `psycopg`_ 3.1.8+ is recommended.
|
2.8.4+ is required, though the latest `psycopg`_ 3.1.8+ is recommended.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -238,6 +238,17 @@ backends.
|
|||||||
|
|
||||||
* ...
|
* ...
|
||||||
|
|
||||||
|
:mod:`django.contrib.gis`
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
* Support for PostGIS 3.0 is removed.
|
||||||
|
|
||||||
|
Dropped support for PostgreSQL 13
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
Upstream support for PostgreSQL 13 ends in November 2025. Django 5.2 supports
|
||||||
|
PostgreSQL 14 and higher.
|
||||||
|
|
||||||
Miscellaneous
|
Miscellaneous
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
@ -548,12 +548,12 @@ class Tests(TestCase):
|
|||||||
|
|
||||||
def test_get_database_version(self):
|
def test_get_database_version(self):
|
||||||
new_connection = no_pool_connection()
|
new_connection = no_pool_connection()
|
||||||
new_connection.pg_version = 130009
|
new_connection.pg_version = 140009
|
||||||
self.assertEqual(new_connection.get_database_version(), (13, 9))
|
self.assertEqual(new_connection.get_database_version(), (14, 9))
|
||||||
|
|
||||||
@mock.patch.object(connection, "get_database_version", return_value=(12,))
|
@mock.patch.object(connection, "get_database_version", return_value=(13,))
|
||||||
def test_check_database_version_supported(self, mocked_get_database_version):
|
def test_check_database_version_supported(self, mocked_get_database_version):
|
||||||
msg = "PostgreSQL 13 or later is required (found 12)."
|
msg = "PostgreSQL 14 or later is required (found 13)."
|
||||||
with self.assertRaisesMessage(NotSupportedError, msg):
|
with self.assertRaisesMessage(NotSupportedError, msg):
|
||||||
connection.check_database_version_supported()
|
connection.check_database_version_supported()
|
||||||
self.assertTrue(mocked_get_database_version.called)
|
self.assertTrue(mocked_get_database_version.called)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from django.db import connection, transaction
|
from django.db import transaction
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
CharField,
|
CharField,
|
||||||
F,
|
F,
|
||||||
@ -13,7 +13,6 @@ from django.db.models import (
|
|||||||
)
|
)
|
||||||
from django.db.models.fields.json import KeyTextTransform, KeyTransform
|
from django.db.models.fields.json import KeyTextTransform, KeyTransform
|
||||||
from django.db.models.functions import Cast, Concat, LPad, Substr
|
from django.db.models.functions import Cast, Concat, LPad, Substr
|
||||||
from django.test import skipUnlessDBFeature
|
|
||||||
from django.test.utils import Approximate
|
from django.test.utils import Approximate
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
@ -95,9 +94,8 @@ class TestGeneralAggregate(PostgreSQLTestCase):
|
|||||||
BoolOr("boolean_field"),
|
BoolOr("boolean_field"),
|
||||||
JSONBAgg("integer_field"),
|
JSONBAgg("integer_field"),
|
||||||
StringAgg("char_field", delimiter=";"),
|
StringAgg("char_field", delimiter=";"),
|
||||||
|
BitXor("integer_field"),
|
||||||
]
|
]
|
||||||
if connection.features.has_bit_xor:
|
|
||||||
tests.append(BitXor("integer_field"))
|
|
||||||
for aggregation in tests:
|
for aggregation in tests:
|
||||||
with self.subTest(aggregation=aggregation):
|
with self.subTest(aggregation=aggregation):
|
||||||
# Empty result with non-execution optimization.
|
# Empty result with non-execution optimization.
|
||||||
@ -133,9 +131,8 @@ class TestGeneralAggregate(PostgreSQLTestCase):
|
|||||||
StringAgg("char_field", delimiter=";", default=Value("<empty>")),
|
StringAgg("char_field", delimiter=";", default=Value("<empty>")),
|
||||||
"<empty>",
|
"<empty>",
|
||||||
),
|
),
|
||||||
|
(BitXor("integer_field", default=0), 0),
|
||||||
]
|
]
|
||||||
if connection.features.has_bit_xor:
|
|
||||||
tests.append((BitXor("integer_field", default=0), 0))
|
|
||||||
for aggregation, expected_result in tests:
|
for aggregation, expected_result in tests:
|
||||||
with self.subTest(aggregation=aggregation):
|
with self.subTest(aggregation=aggregation):
|
||||||
# Empty result with non-execution optimization.
|
# Empty result with non-execution optimization.
|
||||||
@ -348,7 +345,6 @@ class TestGeneralAggregate(PostgreSQLTestCase):
|
|||||||
)
|
)
|
||||||
self.assertEqual(values, {"bitor": 0})
|
self.assertEqual(values, {"bitor": 0})
|
||||||
|
|
||||||
@skipUnlessDBFeature("has_bit_xor")
|
|
||||||
def test_bit_xor_general(self):
|
def test_bit_xor_general(self):
|
||||||
AggregateTestModel.objects.create(integer_field=3)
|
AggregateTestModel.objects.create(integer_field=3)
|
||||||
values = AggregateTestModel.objects.filter(
|
values = AggregateTestModel.objects.filter(
|
||||||
@ -356,14 +352,12 @@ class TestGeneralAggregate(PostgreSQLTestCase):
|
|||||||
).aggregate(bitxor=BitXor("integer_field"))
|
).aggregate(bitxor=BitXor("integer_field"))
|
||||||
self.assertEqual(values, {"bitxor": 2})
|
self.assertEqual(values, {"bitxor": 2})
|
||||||
|
|
||||||
@skipUnlessDBFeature("has_bit_xor")
|
|
||||||
def test_bit_xor_on_only_true_values(self):
|
def test_bit_xor_on_only_true_values(self):
|
||||||
values = AggregateTestModel.objects.filter(
|
values = AggregateTestModel.objects.filter(
|
||||||
integer_field=1,
|
integer_field=1,
|
||||||
).aggregate(bitxor=BitXor("integer_field"))
|
).aggregate(bitxor=BitXor("integer_field"))
|
||||||
self.assertEqual(values, {"bitxor": 1})
|
self.assertEqual(values, {"bitxor": 1})
|
||||||
|
|
||||||
@skipUnlessDBFeature("has_bit_xor")
|
|
||||||
def test_bit_xor_on_only_false_values(self):
|
def test_bit_xor_on_only_false_values(self):
|
||||||
values = AggregateTestModel.objects.filter(
|
values = AggregateTestModel.objects.filter(
|
||||||
integer_field=0,
|
integer_field=0,
|
||||||
|
@ -4,7 +4,7 @@ from unittest import mock
|
|||||||
from django.contrib.postgres.indexes import OpClass
|
from django.contrib.postgres.indexes import OpClass
|
||||||
from django.core.checks import Error
|
from django.core.checks import Error
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import IntegrityError, NotSupportedError, connection, transaction
|
from django.db import IntegrityError, connection, transaction
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
CASCADE,
|
CASCADE,
|
||||||
CharField,
|
CharField,
|
||||||
@ -997,7 +997,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
|
|||||||
RangesModel.objects.create(ints=(10, 19))
|
RangesModel.objects.create(ints=(10, 19))
|
||||||
RangesModel.objects.create(ints=(51, 60))
|
RangesModel.objects.create(ints=(51, 60))
|
||||||
|
|
||||||
@skipUnlessDBFeature("supports_covering_spgist_indexes")
|
|
||||||
def test_range_adjacent_spgist_include(self):
|
def test_range_adjacent_spgist_include(self):
|
||||||
constraint_name = "ints_adjacent_spgist_include"
|
constraint_name = "ints_adjacent_spgist_include"
|
||||||
self.assertNotIn(
|
self.assertNotIn(
|
||||||
@ -1034,7 +1033,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
|
|||||||
editor.add_constraint(RangesModel, constraint)
|
editor.add_constraint(RangesModel, constraint)
|
||||||
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
|
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
|
||||||
|
|
||||||
@skipUnlessDBFeature("supports_covering_spgist_indexes")
|
|
||||||
def test_range_adjacent_spgist_include_condition(self):
|
def test_range_adjacent_spgist_include_condition(self):
|
||||||
constraint_name = "ints_adjacent_spgist_include_condition"
|
constraint_name = "ints_adjacent_spgist_include_condition"
|
||||||
self.assertNotIn(
|
self.assertNotIn(
|
||||||
@ -1067,7 +1065,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
|
|||||||
editor.add_constraint(RangesModel, constraint)
|
editor.add_constraint(RangesModel, constraint)
|
||||||
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
|
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
|
||||||
|
|
||||||
@skipUnlessDBFeature("supports_covering_spgist_indexes")
|
|
||||||
def test_range_adjacent_spgist_include_deferrable(self):
|
def test_range_adjacent_spgist_include_deferrable(self):
|
||||||
constraint_name = "ints_adjacent_spgist_include_deferrable"
|
constraint_name = "ints_adjacent_spgist_include_deferrable"
|
||||||
self.assertNotIn(
|
self.assertNotIn(
|
||||||
@ -1084,27 +1081,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
|
|||||||
editor.add_constraint(RangesModel, constraint)
|
editor.add_constraint(RangesModel, constraint)
|
||||||
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
|
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
|
||||||
|
|
||||||
def test_spgist_include_not_supported(self):
|
|
||||||
constraint_name = "ints_adjacent_spgist_include_not_supported"
|
|
||||||
constraint = ExclusionConstraint(
|
|
||||||
name=constraint_name,
|
|
||||||
expressions=[("ints", RangeOperators.ADJACENT_TO)],
|
|
||||||
index_type="spgist",
|
|
||||||
include=["id"],
|
|
||||||
)
|
|
||||||
msg = (
|
|
||||||
"Covering exclusion constraints using an SP-GiST index require "
|
|
||||||
"PostgreSQL 14+."
|
|
||||||
)
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
with mock.patch(
|
|
||||||
"django.db.backends.postgresql.features.DatabaseFeatures."
|
|
||||||
"supports_covering_spgist_indexes",
|
|
||||||
False,
|
|
||||||
):
|
|
||||||
with self.assertRaisesMessage(NotSupportedError, msg):
|
|
||||||
editor.add_constraint(RangesModel, constraint)
|
|
||||||
|
|
||||||
def test_range_adjacent_opclass(self):
|
def test_range_adjacent_opclass(self):
|
||||||
constraint_name = "ints_adjacent_opclass"
|
constraint_name = "ints_adjacent_opclass"
|
||||||
self.assertNotIn(
|
self.assertNotIn(
|
||||||
@ -1187,7 +1163,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
|
|||||||
editor.add_constraint(RangesModel, constraint)
|
editor.add_constraint(RangesModel, constraint)
|
||||||
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
|
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
|
||||||
|
|
||||||
@skipUnlessDBFeature("supports_covering_spgist_indexes")
|
|
||||||
def test_range_adjacent_spgist_opclass_include(self):
|
def test_range_adjacent_spgist_opclass_include(self):
|
||||||
constraint_name = "ints_adjacent_spgist_opclass_include"
|
constraint_name = "ints_adjacent_spgist_opclass_include"
|
||||||
self.assertNotIn(
|
self.assertNotIn(
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from unittest import mock
|
|
||||||
|
|
||||||
from django.contrib.postgres.indexes import (
|
from django.contrib.postgres.indexes import (
|
||||||
BloomIndex,
|
BloomIndex,
|
||||||
BrinIndex,
|
BrinIndex,
|
||||||
@ -11,10 +9,9 @@ from django.contrib.postgres.indexes import (
|
|||||||
PostgresIndex,
|
PostgresIndex,
|
||||||
SpGistIndex,
|
SpGistIndex,
|
||||||
)
|
)
|
||||||
from django.db import NotSupportedError, connection
|
from django.db import connection
|
||||||
from django.db.models import CharField, F, Index, Q
|
from django.db.models import CharField, F, Index, Q
|
||||||
from django.db.models.functions import Cast, Collate, Length, Lower
|
from django.db.models.functions import Cast, Collate, Length, Lower
|
||||||
from django.test import skipUnlessDBFeature
|
|
||||||
from django.test.utils import register_lookup
|
from django.test.utils import register_lookup
|
||||||
|
|
||||||
from . import PostgreSQLSimpleTestCase, PostgreSQLTestCase
|
from . import PostgreSQLSimpleTestCase, PostgreSQLTestCase
|
||||||
@ -640,7 +637,6 @@ class SchemaTests(PostgreSQLTestCase):
|
|||||||
index_name, self.get_constraints(TextFieldModel._meta.db_table)
|
index_name, self.get_constraints(TextFieldModel._meta.db_table)
|
||||||
)
|
)
|
||||||
|
|
||||||
@skipUnlessDBFeature("supports_covering_spgist_indexes")
|
|
||||||
def test_spgist_include(self):
|
def test_spgist_include(self):
|
||||||
index_name = "scene_spgist_include_setting"
|
index_name = "scene_spgist_include_setting"
|
||||||
index = SpGistIndex(name=index_name, fields=["scene"], include=["setting"])
|
index = SpGistIndex(name=index_name, fields=["scene"], include=["setting"])
|
||||||
@ -654,20 +650,6 @@ class SchemaTests(PostgreSQLTestCase):
|
|||||||
editor.remove_index(Scene, index)
|
editor.remove_index(Scene, index)
|
||||||
self.assertNotIn(index_name, self.get_constraints(Scene._meta.db_table))
|
self.assertNotIn(index_name, self.get_constraints(Scene._meta.db_table))
|
||||||
|
|
||||||
def test_spgist_include_not_supported(self):
|
|
||||||
index_name = "spgist_include_exception"
|
|
||||||
index = SpGistIndex(fields=["scene"], name=index_name, include=["setting"])
|
|
||||||
msg = "Covering SP-GiST indexes require PostgreSQL 14+."
|
|
||||||
with self.assertRaisesMessage(NotSupportedError, msg):
|
|
||||||
with mock.patch(
|
|
||||||
"django.db.backends.postgresql.features.DatabaseFeatures."
|
|
||||||
"supports_covering_spgist_indexes",
|
|
||||||
False,
|
|
||||||
):
|
|
||||||
with connection.schema_editor() as editor:
|
|
||||||
editor.add_index(Scene, index)
|
|
||||||
self.assertNotIn(index_name, self.get_constraints(Scene._meta.db_table))
|
|
||||||
|
|
||||||
def test_custom_suffix(self):
|
def test_custom_suffix(self):
|
||||||
class CustomSuffixIndex(PostgresIndex):
|
class CustomSuffixIndex(PostgresIndex):
|
||||||
suffix = "sfx"
|
suffix = "sfx"
|
||||||
|
Loading…
Reference in New Issue
Block a user