Made isvalid lookup use IsValid function to decrease code redundancy.

This commit is contained in:
Sergey Fedoseev 2017-03-29 17:56:58 +05:00 committed by Tim Graham
parent 1d070d027c
commit 9cd6ba991f
8 changed files with 19 additions and 32 deletions

View File

@ -68,7 +68,7 @@ class BaseSpatialFeatures:
@property @property
def supports_isvalid_lookup(self): 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? # Is the aggregate supported by the database?
@property @property

View File

@ -51,10 +51,6 @@ class SDORelate(SpatialOperator):
return super().as_sql(connection, lookup, template_params, sql_params) 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): class OracleOperations(BaseSpatialOperations, DatabaseOperations):
name = 'oracle' name = 'oracle'
@ -100,7 +96,6 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
'covers': SDOOperator(func='SDO_COVERS'), 'covers': SDOOperator(func='SDO_COVERS'),
'disjoint': SDODisjoint(), 'disjoint': SDODisjoint(),
'intersects': SDOOperator(func='SDO_OVERLAPBDYINTERSECT'), # TODO: Is this really the same as ST_Intersects()? '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'), 'equals': SDOOperator(func='SDO_EQUAL'),
'exact': SDOOperator(func='SDO_EQUAL'), 'exact': SDOOperator(func='SDO_EQUAL'),
'overlaps': SDOOperator(func='SDO_OVERLAPS'), 'overlaps': SDOOperator(func='SDO_OVERLAPS'),

View File

@ -134,7 +134,6 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
'disjoint': PostGISOperator(func='ST_Disjoint', raster=BILATERAL), 'disjoint': PostGISOperator(func='ST_Disjoint', raster=BILATERAL),
'equals': PostGISOperator(func='ST_Equals'), 'equals': PostGISOperator(func='ST_Equals'),
'intersects': PostGISOperator(func='ST_Intersects', geography=True, raster=BILATERAL), 'intersects': PostGISOperator(func='ST_Intersects', geography=True, raster=BILATERAL),
'isvalid': PostGISOperator(func='ST_IsValid'),
'overlaps': PostGISOperator(func='ST_Overlaps', raster=BILATERAL), 'overlaps': PostGISOperator(func='ST_Overlaps', raster=BILATERAL),
'relate': PostGISOperator(func='ST_Relate'), 'relate': PostGISOperator(func='ST_Relate'),
'touches': PostGISOperator(func='ST_Touches', raster=BILATERAL), 'touches': PostGISOperator(func='ST_Touches', raster=BILATERAL),

View File

@ -48,8 +48,6 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
select = 'AsText(%s)' select = 'AsText(%s)'
gis_operators = { gis_operators = {
# Unary predicates
'isvalid': SpatialOperator(func='IsValid'),
# Binary predicates # Binary predicates
'equals': SpatialOperator(func='Equals'), 'equals': SpatialOperator(func='Equals'),
'disjoint': SpatialOperator(func='Disjoint'), 'disjoint': SpatialOperator(func='Disjoint'),

View File

@ -1,5 +1,6 @@
from django.db.models import * # NOQA isort:skip from django.db.models import * # NOQA isort:skip
from django.db.models import __all__ as models_all # 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 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 * # NOQA
from django.contrib.gis.db.models.aggregates import __all__ as aggregates_all from django.contrib.gis.db.models.aggregates import __all__ as aggregates_all

View File

@ -1,19 +1,23 @@
from decimal import Decimal 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.db.models.sql import AreaField
from django.contrib.gis.geometry.backend import Geometry from django.contrib.gis.geometry.backend import Geometry
from django.contrib.gis.measure import ( from django.contrib.gis.measure import (
Area as AreaMeasure, Distance as DistanceMeasure, Area as AreaMeasure, Distance as DistanceMeasure,
) )
from django.core.exceptions import FieldError 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 from django.db.models.expressions import Func, Value
NUMERIC_TYPES = (int, float, Decimal) NUMERIC_TYPES = (int, float, Decimal)
class GeoFunc(Func): class GeoFuncMixin:
function = None function = None
output_field_class = None output_field_class = None
geom_param_pos = 0 geom_param_pos = 0
@ -70,6 +74,10 @@ class GeoFunc(Func):
return value return value
class GeoFunc(GeoFuncMixin, Func):
pass
class GeomValue(Value): class GeomValue(Value):
geography = False geography = False
@ -319,8 +327,10 @@ class Intersection(OracleToleranceMixin, GeoFuncWithGeoParam):
arity = 2 arity = 2
class IsValid(OracleToleranceMixin, GeoFunc): @BaseSpatialField.register_lookup
output_field_class = BooleanField class IsValid(OracleToleranceMixin, GeoFuncMixin, Transform):
lookup_name = 'isvalid'
output_field = BooleanField()
def as_oracle(self, compiler, connection, **extra_context): def as_oracle(self, compiler, connection, **extra_context):
sql, params = super().as_oracle(compiler, connection, **extra_context) sql, params = super().as_oracle(compiler, connection, **extra_context)

View File

@ -261,22 +261,6 @@ class IntersectsLookup(GISLookup):
lookup_name = 'intersects' lookup_name = 'intersects'
@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 @BaseSpatialField.register_lookup
class OverlapsLookup(GISLookup): class OverlapsLookup(GISLookup):
lookup_name = 'overlaps' lookup_name = 'overlaps'

View File

@ -271,8 +271,8 @@ class RasterFieldTest(TransactionTestCase):
def test_isvalid_lookup_with_raster_error(self): def test_isvalid_lookup_with_raster_error(self):
qs = RasterModel.objects.filter(rast__isvalid=True) qs = RasterModel.objects.filter(rast__isvalid=True)
msg = 'The isvalid lookup is only available on geometry fields.' msg = 'Geometry functions not supported for raster fields.'
with self.assertRaisesMessage(ValueError, msg): with self.assertRaisesMessage(TypeError, msg):
qs.count() qs.count()
def test_result_of_gis_lookup_with_rasters(self): def test_result_of_gis_lookup_with_rasters(self):