Fixed #25636 -- Dropped support for SpatiaLite < 3.0

This commit is contained in:
Sergey Fedoseev 2015-10-31 00:04:00 +05:00 committed by Claude Paroz
parent b67502fb8d
commit 8ad923b9d0
10 changed files with 25 additions and 68 deletions

View File

@ -1,6 +1,5 @@
""" """
SQL functions reference lists: SQL functions reference lists:
http://www.gaia-gis.it/spatialite-2.4.0/spatialite-sql-2.4.html
http://www.gaia-gis.it/spatialite-3.0.0-BETA/spatialite-sql-3.0.0.html http://www.gaia-gis.it/spatialite-3.0.0-BETA/spatialite-sql-3.0.0.html
http://www.gaia-gis.it/gaia-sins/spatialite-sql-4.2.1.html http://www.gaia-gis.it/gaia-sins/spatialite-sql-4.2.1.html
""" """
@ -16,7 +15,6 @@ from django.contrib.gis.geometry.backend import Geometry
from django.contrib.gis.measure import Distance from django.contrib.gis.measure import Distance
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
from django.db.backends.sqlite3.operations import DatabaseOperations from django.db.backends.sqlite3.operations import DatabaseOperations
from django.db.utils import DatabaseError
from django.utils import six from django.utils import six
from django.utils.functional import cached_property from django.utils.functional import cached_property
@ -37,7 +35,10 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
distance = 'Distance' distance = 'Distance'
envelope = 'Envelope' envelope = 'Envelope'
extent = 'Extent' extent = 'Extent'
geojson = 'AsGeoJSON'
gml = 'AsGML'
intersection = 'Intersection' intersection = 'Intersection'
kml = 'AsKML'
length = 'GLength' # OpenGis defines Length, but this conflicts with an SQLite reserved keyword length = 'GLength' # OpenGis defines Length, but this conflicts with an SQLite reserved keyword
num_geom = 'NumGeometries' num_geom = 'NumGeometries'
num_points = 'NumPoints' num_points = 'NumPoints'
@ -110,44 +111,15 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
'database (error was "%s"). Was the SpatiaLite initialization ' 'database (error was "%s"). Was the SpatiaLite initialization '
'SQL loaded on this database?') % (self.connection.settings_dict['NAME'], msg) 'SQL loaded on this database?') % (self.connection.settings_dict['NAME'], msg)
six.reraise(ImproperlyConfigured, ImproperlyConfigured(new_msg), sys.exc_info()[2]) six.reraise(ImproperlyConfigured, ImproperlyConfigured(new_msg), sys.exc_info()[2])
if version < (2, 4, 0): if version < (3, 0, 0):
raise ImproperlyConfigured('GeoDjango only supports SpatiaLite versions ' raise ImproperlyConfigured('GeoDjango only supports SpatiaLite versions 3.0.0 and above.')
'2.4.0 and above')
return version return version
@property
def _version_greater_2_4_0_rc4(self):
if self.spatial_version >= (2, 4, 1):
return True
else:
# Spatialite 2.4.0-RC4 added AsGML and AsKML, however both
# RC2 (shipped in popular Debian/Ubuntu packages) and RC4
# report version as '2.4.0', so we fall back to feature detection
try:
self._get_spatialite_func("AsGML(GeomFromText('POINT(1 1)'))")
except DatabaseError:
return False
return True
@cached_property @cached_property
def disallowed_aggregates(self): def disallowed_aggregates(self):
disallowed = (aggregates.Extent3D, aggregates.MakeLine) disallowed = (aggregates.Extent3D, aggregates.MakeLine)
if self.spatial_version < (3, 0, 0):
disallowed += (aggregates.Collect, aggregates.Extent)
return disallowed return disallowed
@cached_property
def gml(self):
return 'AsGML' if self._version_greater_2_4_0_rc4 else None
@cached_property
def kml(self):
return 'AsKML' if self._version_greater_2_4_0_rc4 else None
@cached_property
def geojson(self):
return 'AsGeoJSON' if self.spatial_version >= (3, 0, 0) else None
def convert_extent(self, box, srid): def convert_extent(self, box, srid):
""" """
Convert the polygon data received from Spatialite to min/max values. Convert the polygon data received from Spatialite to min/max values.

View File

@ -113,8 +113,7 @@ class GeoQuerySet(QuerySet):
""" """
backend = connections[self.db].ops backend = connections[self.db].ops
if not backend.geojson: if not backend.geojson:
raise NotImplementedError('Only PostGIS 1.3.4+ and SpatiaLite 3.0+ ' raise NotImplementedError('Only PostGIS and SpatiaLite support GeoJSON serialization.')
'support GeoJSON serialization.')
if not isinstance(precision, six.integer_types): if not isinstance(precision, six.integer_types):
raise TypeError('Precision keyword must be set with an integer.') raise TypeError('Precision keyword must be set with an integer.')

View File

@ -345,8 +345,8 @@ support any of these aggregates, and is thus excluded from the table.
======================= ======= ====== ========== ======================= ======= ====== ==========
Aggregate PostGIS Oracle SpatiaLite Aggregate PostGIS Oracle SpatiaLite
======================= ======= ====== ========== ======================= ======= ====== ==========
:class:`Collect` X (from v3.0) :class:`Collect` X X
:class:`Extent` X X (from v3.0) :class:`Extent` X X X
:class:`Extent3D` X :class:`Extent3D` X
:class:`MakeLine` X :class:`MakeLine` X
:class:`Union` X X X :class:`Union` X X X

View File

@ -1251,7 +1251,7 @@ Example::
.. class:: Collect(geo_field) .. class:: Collect(geo_field)
*Availability*: PostGIS, Spatialite (≥3.0) *Availability*: PostGIS, Spatialite
Returns a ``GEOMETRYCOLLECTION`` or a ``MULTI`` geometry object from the geometry Returns a ``GEOMETRYCOLLECTION`` or a ``MULTI`` geometry object from the geometry
column. This is analogous to a simplified version of the :class:`Union` column. This is analogous to a simplified version of the :class:`Union`
@ -1264,7 +1264,7 @@ not caring about dissolving boundaries.
.. class:: Extent(geo_field) .. class:: Extent(geo_field)
*Availability*: PostGIS, Oracle, Spatialite (≥3.0) *Availability*: PostGIS, Oracle, Spatialite
Returns the extent of all ``geo_field`` in the ``QuerySet`` as a four-tuple, Returns the extent of all ``geo_field`` in the ``QuerySet`` as a four-tuple,
comprising the lower left coordinate and the upper right coordinate. comprising the lower left coordinate and the upper right coordinate.

View File

@ -13,7 +13,7 @@ Program Description Required
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes (SQLite only) 2.0, 1.11, 1.10, 1.9, 1.8, 1.7 :doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes (SQLite only) 2.0, 1.11, 1.10, 1.9, 1.8, 1.7
:doc:`GeoIP <../geoip>` IP-based geolocation library No 1.4 :doc:`GeoIP <../geoip>` IP-based geolocation library No 1.4
`PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 2.1, 2.0 `PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 2.1, 2.0
`SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 4.1, 4.0, 3.0, 2.4 `SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 4.1, 4.0, 3.0
======================== ==================================== ================================ ============================ ======================== ==================================== ================================ ============================
Note that older or more recent versions of these libraries *may* also work Note that older or more recent versions of these libraries *may* also work
@ -31,7 +31,6 @@ totally fine with GeoDjango. Your mileage may vary.
GDAL 1.11.0 2014-04-25 GDAL 1.11.0 2014-04-25
PostGIS 2.0.0 2012-04-03 PostGIS 2.0.0 2012-04-03
PostGIS 2.1.0 2013-08-17 PostGIS 2.1.0 2013-08-17
Spatialite 2.4.0 2010-11-14
Spatialite 3.0.0 2011-12-30 Spatialite 3.0.0 2011-12-30
Spatialite 4.0.0 2012-11-25 Spatialite 4.0.0 2012-11-25
Spatialite 4.1.0 2013-06-04 Spatialite 4.1.0 2013-06-04

View File

@ -61,7 +61,7 @@ Database Library Requirements Supported Versions Notes
PostgreSQL GEOS, PROJ.4, PostGIS 9.1+ Requires PostGIS. PostgreSQL GEOS, PROJ.4, PostGIS 9.1+ Requires PostGIS.
MySQL GEOS 5.5+ Not OGC-compliant; :ref:`limited functionality <mysql-spatial-limitations>`. MySQL GEOS 5.5+ Not OGC-compliant; :ref:`limited functionality <mysql-spatial-limitations>`.
Oracle GEOS 11.2+ XE not supported. Oracle GEOS 11.2+ XE not supported.
SQLite GEOS, GDAL, PROJ.4, SpatiaLite 3.6.+ Requires SpatiaLite 2.4+, pysqlite2 2.5+ SQLite GEOS, GDAL, PROJ.4, SpatiaLite 3.6.+ Requires SpatiaLite 3.0+, pysqlite2 2.5+
================== ============================== ================== ========================================= ================== ============================== ================== =========================================
See also `this comparison matrix`__ on the OSGeo Wiki for See also `this comparison matrix`__ on the OSGeo Wiki for

View File

@ -297,6 +297,10 @@ Miscellaneous
* The ``repr()`` of a ``QuerySet`` is wrapped in ``<QuerySet >`` to * The ``repr()`` of a ``QuerySet`` is wrapped in ``<QuerySet >`` to
disambiguate it from a plain list when debugging. disambiguate it from a plain list when debugging.
:mod:`django.contrib.gis`
~~~~~~~~~~~~~~~~~~~~~~~~~
* Support for SpatiaLite < 3.0 is dropped.
.. _deprecated-features-1.10: .. _deprecated-features-1.10:
Features deprecated in 1.10 Features deprecated in 1.10

View File

@ -10,7 +10,7 @@ from django.db.models import F, Q
from django.test import TestCase, ignore_warnings, skipUnlessDBFeature from django.test import TestCase, ignore_warnings, skipUnlessDBFeature
from django.utils.deprecation import RemovedInDjango20Warning from django.utils.deprecation import RemovedInDjango20Warning
from ..utils import no_oracle, oracle, postgis, spatialite from ..utils import no_oracle, oracle, postgis
from .models import ( from .models import (
AustraliaCity, CensusZipcode, Interstate, SouthTexasCity, SouthTexasCityFt, AustraliaCity, CensusZipcode, Interstate, SouthTexasCity, SouthTexasCityFt,
SouthTexasInterstate, SouthTexasZipcode, SouthTexasInterstate, SouthTexasZipcode,
@ -123,7 +123,7 @@ class DistanceTest(TestCase):
# with different projected coordinate systems. # with different projected coordinate systems.
dist1 = SouthTexasCity.objects.distance(lagrange, field_name='point').order_by('id') dist1 = SouthTexasCity.objects.distance(lagrange, field_name='point').order_by('id')
dist2 = SouthTexasCity.objects.distance(lagrange).order_by('id') # Using GEOSGeometry parameter dist2 = SouthTexasCity.objects.distance(lagrange).order_by('id') # Using GEOSGeometry parameter
if spatialite or oracle: if oracle:
dist_qs = [dist1, dist2] dist_qs = [dist1, dist2]
else: else:
dist3 = SouthTexasCityFt.objects.distance(lagrange.ewkt).order_by('id') # Using EWKT string parameter. dist3 = SouthTexasCityFt.objects.distance(lagrange.ewkt).order_by('id') # Using EWKT string parameter.
@ -247,9 +247,8 @@ class DistanceTest(TestCase):
point__distance_lte=(self.stx_pnt, D(km=20)), point__distance_lte=(self.stx_pnt, D(km=20)),
) )
# Can't determine the units on SpatiaLite from PROJ.4 string, and
# Oracle 11 incorrectly thinks it is not projected. # Oracle 11 incorrectly thinks it is not projected.
if spatialite or oracle: if oracle:
dist_qs = (qs1,) dist_qs = (qs1,)
else: else:
qs2 = SouthTexasCityFt.objects.filter(point__distance_gte=(self.stx_pnt, D(km=7))).filter( qs2 = SouthTexasCityFt.objects.filter(point__distance_gte=(self.stx_pnt, D(km=7))).filter(
@ -513,7 +512,7 @@ class DistanceFunctionsTests(TestCase):
# Testing using different variations of parameters and using models # Testing using different variations of parameters and using models
# with different projected coordinate systems. # with different projected coordinate systems.
dist1 = SouthTexasCity.objects.annotate(distance=Distance('point', lagrange)).order_by('id') dist1 = SouthTexasCity.objects.annotate(distance=Distance('point', lagrange)).order_by('id')
if spatialite or oracle: if oracle:
dist_qs = [dist1] dist_qs = [dist1]
else: else:
dist2 = SouthTexasCityFt.objects.annotate(distance=Distance('point', lagrange)).order_by('id') dist2 = SouthTexasCityFt.objects.annotate(distance=Distance('point', lagrange)).order_by('id')

View File

@ -27,7 +27,7 @@ class GISFunctionsTests(TestCase):
fixtures = ['initial'] fixtures = ['initial']
def test_asgeojson(self): def test_asgeojson(self):
# Only PostGIS and SpatiaLite 3.0+ support GeoJSON. # Only PostGIS and SpatiaLite support GeoJSON.
if not connection.ops.geojson: if not connection.ops.geojson:
with self.assertRaises(NotImplementedError): with self.assertRaises(NotImplementedError):
list(Country.objects.annotate(json=functions.AsGeoJSON('mpoly'))) list(Country.objects.annotate(json=functions.AsGeoJSON('mpoly')))
@ -108,12 +108,6 @@ class GISFunctionsTests(TestCase):
r'<gml:coordinates decimal="\." cs="," ts=" ">-104.60925\d+,38.25500\d+ ' r'<gml:coordinates decimal="\." cs="," ts=" ">-104.60925\d+,38.25500\d+ '
r'</gml:coordinates></gml:Point>' r'</gml:coordinates></gml:Point>'
) )
elif spatialite and connection.ops.spatial_version < (3, 0, 0):
# Spatialite before 3.0 has extra colon in SrsName
gml_regex = re.compile(
r'^<gml:Point SrsName="EPSG::4326"><gml:coordinates decimal="\." '
r'cs="," ts=" ">-104.609251\d+,38.255001</gml:coordinates></gml:Point>'
)
else: else:
gml_regex = re.compile( gml_regex = re.compile(
r'^<gml:Point srsName="EPSG:4326"><gml:coordinates>' r'^<gml:Point srsName="EPSG:4326"><gml:coordinates>'

View File

@ -149,9 +149,6 @@ class GeoModelTest(TestCase):
# If the GeometryField SRID is -1, then we shouldn't perform any # If the GeometryField SRID is -1, then we shouldn't perform any
# transformation if the SRID of the input geometry is different. # transformation if the SRID of the input geometry is different.
if spatialite and connection.ops.spatial_version < (3, 0, 0):
# SpatiaLite < 3 does not support missing SRID values.
return
m1 = MinusOneSRID(geom=Point(17, 23, srid=4326)) m1 = MinusOneSRID(geom=Point(17, 23, srid=4326))
m1.save() m1.save()
self.assertEqual(-1, m1.geom.srid) self.assertEqual(-1, m1.geom.srid)
@ -272,10 +269,9 @@ class GeoLookupTest(TestCase):
self.assertEqual('Texas', tx.name) self.assertEqual('Texas', tx.name)
self.assertEqual('New Zealand', nz.name) self.assertEqual('New Zealand', nz.name)
# Spatialite 2.3 thinks that Lawrence is in Puerto Rico (a NULL geometry). # Testing `contains` on the states using the point for Lawrence.
if not (spatialite and connection.ops.spatial_version < (3, 0, 0)): ks = State.objects.get(poly__contains=lawrence.point)
ks = State.objects.get(poly__contains=lawrence.point) self.assertEqual('Kansas', ks.name)
self.assertEqual('Kansas', ks.name)
# Pueblo and Oklahoma City (even though OK City is within the bounding box of Texas) # Pueblo and Oklahoma City (even though OK City is within the bounding box of Texas)
# are not contained in Texas or New Zealand. # are not contained in Texas or New Zealand.
@ -558,7 +554,7 @@ class GeoQuerySetTest(TestCase):
def test_geojson(self): def test_geojson(self):
"Testing GeoJSON output from the database using GeoQuerySet.geojson()." "Testing GeoJSON output from the database using GeoQuerySet.geojson()."
# Only PostGIS and SpatiaLite 3.0+ support GeoJSON. # Only PostGIS and SpatiaLite support GeoJSON.
if not connection.ops.geojson: if not connection.ops.geojson:
self.assertRaises(NotImplementedError, Country.objects.all().geojson, field_name='mpoly') self.assertRaises(NotImplementedError, Country.objects.all().geojson, field_name='mpoly')
return return
@ -625,12 +621,6 @@ class GeoQuerySetTest(TestCase):
r'<gml:coordinates decimal="\." cs="," ts=" ">-104.60925\d+,38.25500\d+ ' r'<gml:coordinates decimal="\." cs="," ts=" ">-104.60925\d+,38.25500\d+ '
r'</gml:coordinates></gml:Point>' r'</gml:coordinates></gml:Point>'
) )
elif spatialite and connection.ops.spatial_version < (3, 0, 0):
# Spatialite before 3.0 has extra colon in SrsName
gml_regex = re.compile(
r'^<gml:Point SrsName="EPSG::4326"><gml:coordinates decimal="\." '
r'cs="," ts=" ">-104.609251\d+,38.255001</gml:coordinates></gml:Point>'
)
else: else:
gml_regex = re.compile( gml_regex = re.compile(
r'^<gml:Point srsName="EPSG:4326"><gml:coordinates>' r'^<gml:Point srsName="EPSG:4326"><gml:coordinates>'