summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/contrib/gis/db/backends/base/features.py2
-rw-r--r--django/contrib/gis/db/backends/oracle/operations.py5
-rw-r--r--django/contrib/gis/db/backends/postgis/operations.py1
-rw-r--r--django/contrib/gis/db/backends/spatialite/operations.py2
-rw-r--r--django/contrib/gis/db/models/__init__.py1
-rw-r--r--django/contrib/gis/db/models/functions.py20
-rw-r--r--django/contrib/gis/db/models/lookups.py16
-rw-r--r--tests/gis_tests/rasterapp/test_rasterfield.py4
8 files changed, 19 insertions, 32 deletions
diff --git a/django/contrib/gis/db/backends/base/features.py b/django/contrib/gis/db/backends/base/features.py
index 4b4ffcc49f..7498fb2514 100644
--- a/django/contrib/gis/db/backends/base/features.py
+++ b/django/contrib/gis/db/backends/base/features.py
@@ -68,7 +68,7 @@ class BaseSpatialFeatures:
@property
def supports_isvalid_lookup(self):
- return 'isvalid' in self.connection.ops.gis_operators
+ return self.has_IsValid_function
# Is the aggregate supported by the database?
@property
diff --git a/django/contrib/gis/db/backends/oracle/operations.py b/django/contrib/gis/db/backends/oracle/operations.py
index e030af1da3..62506e4227 100644
--- a/django/contrib/gis/db/backends/oracle/operations.py
+++ b/django/contrib/gis/db/backends/oracle/operations.py
@@ -51,10 +51,6 @@ class SDORelate(SpatialOperator):
return super().as_sql(connection, lookup, template_params, sql_params)
-class SDOIsValid(SpatialOperator):
- sql_template = "%%(func)s(%%(lhs)s, %s) = 'TRUE'" % DEFAULT_TOLERANCE
-
-
class OracleOperations(BaseSpatialOperations, DatabaseOperations):
name = 'oracle'
@@ -100,7 +96,6 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
'covers': SDOOperator(func='SDO_COVERS'),
'disjoint': SDODisjoint(),
'intersects': SDOOperator(func='SDO_OVERLAPBDYINTERSECT'), # TODO: Is this really the same as ST_Intersects()?
- 'isvalid': SDOIsValid(func='SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT'),
'equals': SDOOperator(func='SDO_EQUAL'),
'exact': SDOOperator(func='SDO_EQUAL'),
'overlaps': SDOOperator(func='SDO_OVERLAPS'),
diff --git a/django/contrib/gis/db/backends/postgis/operations.py b/django/contrib/gis/db/backends/postgis/operations.py
index d002c5d18c..62f569c754 100644
--- a/django/contrib/gis/db/backends/postgis/operations.py
+++ b/django/contrib/gis/db/backends/postgis/operations.py
@@ -134,7 +134,6 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
'disjoint': PostGISOperator(func='ST_Disjoint', raster=BILATERAL),
'equals': PostGISOperator(func='ST_Equals'),
'intersects': PostGISOperator(func='ST_Intersects', geography=True, raster=BILATERAL),
- 'isvalid': PostGISOperator(func='ST_IsValid'),
'overlaps': PostGISOperator(func='ST_Overlaps', raster=BILATERAL),
'relate': PostGISOperator(func='ST_Relate'),
'touches': PostGISOperator(func='ST_Touches', raster=BILATERAL),
diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py
index d2fc68b4c0..46cac8c0b3 100644
--- a/django/contrib/gis/db/backends/spatialite/operations.py
+++ b/django/contrib/gis/db/backends/spatialite/operations.py
@@ -48,8 +48,6 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
select = 'AsText(%s)'
gis_operators = {
- # Unary predicates
- 'isvalid': SpatialOperator(func='IsValid'),
# Binary predicates
'equals': SpatialOperator(func='Equals'),
'disjoint': SpatialOperator(func='Disjoint'),
diff --git a/django/contrib/gis/db/models/__init__.py b/django/contrib/gis/db/models/__init__.py
index 31ca0001df..2e472557d8 100644
--- a/django/contrib/gis/db/models/__init__.py
+++ b/django/contrib/gis/db/models/__init__.py
@@ -1,5 +1,6 @@
from django.db.models import * # NOQA isort:skip
from django.db.models import __all__ as models_all # isort:skip
+import django.contrib.gis.db.models.functions # NOQA
import django.contrib.gis.db.models.lookups # NOQA
from django.contrib.gis.db.models.aggregates import * # NOQA
from django.contrib.gis.db.models.aggregates import __all__ as aggregates_all
diff --git a/django/contrib/gis/db/models/functions.py b/django/contrib/gis/db/models/functions.py
index b688299cb5..fdcb562162 100644
--- a/django/contrib/gis/db/models/functions.py
+++ b/django/contrib/gis/db/models/functions.py
@@ -1,19 +1,23 @@
from decimal import Decimal
-from django.contrib.gis.db.models.fields import GeometryField, RasterField
+from django.contrib.gis.db.models.fields import (
+ BaseSpatialField, GeometryField, RasterField,
+)
from django.contrib.gis.db.models.sql import AreaField
from django.contrib.gis.geometry.backend import Geometry
from django.contrib.gis.measure import (
Area as AreaMeasure, Distance as DistanceMeasure,
)
from django.core.exceptions import FieldError
-from django.db.models import BooleanField, FloatField, IntegerField, TextField
+from django.db.models import (
+ BooleanField, FloatField, IntegerField, TextField, Transform,
+)
from django.db.models.expressions import Func, Value
NUMERIC_TYPES = (int, float, Decimal)
-class GeoFunc(Func):
+class GeoFuncMixin:
function = None
output_field_class = None
geom_param_pos = 0
@@ -70,6 +74,10 @@ class GeoFunc(Func):
return value
+class GeoFunc(GeoFuncMixin, Func):
+ pass
+
+
class GeomValue(Value):
geography = False
@@ -319,8 +327,10 @@ class Intersection(OracleToleranceMixin, GeoFuncWithGeoParam):
arity = 2
-class IsValid(OracleToleranceMixin, GeoFunc):
- output_field_class = BooleanField
+@BaseSpatialField.register_lookup
+class IsValid(OracleToleranceMixin, GeoFuncMixin, Transform):
+ lookup_name = 'isvalid'
+ output_field = BooleanField()
def as_oracle(self, compiler, connection, **extra_context):
sql, params = super().as_oracle(compiler, connection, **extra_context)
diff --git a/django/contrib/gis/db/models/lookups.py b/django/contrib/gis/db/models/lookups.py
index c0d1934965..2024df45b0 100644
--- a/django/contrib/gis/db/models/lookups.py
+++ b/django/contrib/gis/db/models/lookups.py
@@ -262,22 +262,6 @@ class IntersectsLookup(GISLookup):
@BaseSpatialField.register_lookup
-class IsValidLookup(GISLookup):
- lookup_name = 'isvalid'
- sql_template = '%(func)s(%(lhs)s)'
-
- def as_sql(self, compiler, connection):
- if self.lhs.field.geom_type == 'RASTER':
- raise ValueError('The isvalid lookup is only available on geometry fields.')
- gis_op = connection.ops.gis_operators[self.lookup_name]
- sql, params = self.process_lhs(compiler, connection)
- sql, params = gis_op.as_sql(connection, self, {'func': gis_op.func, 'lhs': sql}, params)
- if not self.rhs:
- sql = 'NOT ' + sql
- return sql, params
-
-
-@BaseSpatialField.register_lookup
class OverlapsLookup(GISLookup):
lookup_name = 'overlaps'
diff --git a/tests/gis_tests/rasterapp/test_rasterfield.py b/tests/gis_tests/rasterapp/test_rasterfield.py
index 975b68cab0..1e4ffbfbd7 100644
--- a/tests/gis_tests/rasterapp/test_rasterfield.py
+++ b/tests/gis_tests/rasterapp/test_rasterfield.py
@@ -271,8 +271,8 @@ class RasterFieldTest(TransactionTestCase):
def test_isvalid_lookup_with_raster_error(self):
qs = RasterModel.objects.filter(rast__isvalid=True)
- msg = 'The isvalid lookup is only available on geometry fields.'
- with self.assertRaisesMessage(ValueError, msg):
+ msg = 'Geometry functions not supported for raster fields.'
+ with self.assertRaisesMessage(TypeError, msg):
qs.count()
def test_result_of_gis_lookup_with_rasters(self):