diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py index 1413f2227b4..6dc5048b1b7 100644 --- a/django/contrib/gis/db/backends/spatialite/operations.py +++ b/django/contrib/gis/db/backends/spatialite/operations.py @@ -80,19 +80,23 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations): 'distance_lte': SpatialOperator(func='Distance', op='<='), } - function_names = { - 'Length': 'ST_Length', - 'Reverse': 'ST_Reverse', - 'Scale': 'ScaleCoords', - 'Translate': 'ST_Translate', - 'Union': 'ST_Union', - } + @cached_property + def function_names(self): + return { + 'Length': 'ST_Length', + 'Reverse': 'ST_Reverse', + 'Scale': 'ScaleCoords', + 'Translate': 'ST_Translate' if self.spatial_version >= (3, 1, 0) else 'ShiftCoords', + 'Union': 'ST_Union', + } @cached_property def unsupported_functions(self): unsupported = {'BoundingCircle', 'ForceRHR', 'GeoHash', 'MemSize'} + if self.spatial_version < (3, 1, 0): + unsupported.add('SnapToGrid') if self.spatial_version < (4, 0, 0): - unsupported.add('Reverse') + unsupported.update({'Perimeter', 'Reverse'}) return unsupported @cached_property diff --git a/django/contrib/gis/db/models/functions.py b/django/contrib/gis/db/models/functions.py index 4902520b86c..792edac929a 100644 --- a/django/contrib/gis/db/models/functions.py +++ b/django/contrib/gis/db/models/functions.py @@ -403,9 +403,12 @@ class Transform(GeoFunc): class Translate(Scale): def as_sqlite(self, compiler, connection): - # Always provide the z parameter - if len(self.source_expressions) < 4: + func_name = connection.ops.spatial_function_name(self.name) + if func_name == 'ST_Translate' and len(self.source_expressions) < 4: + # Always provide the z parameter for ST_Translate (Spatialite >= 3.1) self.source_expressions.append(Value(0)) + elif func_name == 'ShiftCoords' and len(self.source_expressions) > 3: + raise ValueError("This version of Spatialite doesn't support 3D") return super(Translate, self).as_sqlite(compiler, connection) diff --git a/tests/gis_tests/geoapp/test_functions.py b/tests/gis_tests/geoapp/test_functions.py index b17a1a2fc08..edef090c5be 100644 --- a/tests/gis_tests/geoapp/test_functions.py +++ b/tests/gis_tests/geoapp/test_functions.py @@ -2,6 +2,7 @@ from __future__ import unicode_literals import re from decimal import Decimal +from unittest import skipUnless from django.contrib.gis.db.models import functions from django.contrib.gis.geos import HAS_GEOS @@ -12,7 +13,9 @@ from django.utils import six from ..utils import mysql, oracle, postgis, spatialite if HAS_GEOS: - from django.contrib.gis.geos import LineString, Point, Polygon, fromstr + from django.contrib.gis.geos import ( + LineString, Point, Polygon, fromstr, geos_version_info, + ) from .models import Country, City, State, Track @@ -382,6 +385,7 @@ class GISFunctionsTests(TestCase): ) @skipUnlessDBFeature("has_SymDifference_function") + @skipUnless(HAS_GEOS and geos_version_info()['version'] >= '3.3.0', "GEOS >= 3.3 required") def test_sym_difference(self): geom = Point(5, 23, srid=4326) qs = Country.objects.annotate(sym_difference=functions.SymDifference('mpoly', geom))