Fixed #32575 -- Added support for SpatiaLite 5.
This commit is contained in:
parent
b9d156761f
commit
30e123ed35
|
@ -71,4 +71,7 @@ class DatabaseWrapper(SQLiteDatabaseWrapper):
|
||||||
with self.cursor() as cursor:
|
with self.cursor() as cursor:
|
||||||
cursor.execute("PRAGMA table_info(geometry_columns);")
|
cursor.execute("PRAGMA table_info(geometry_columns);")
|
||||||
if cursor.fetchall() == []:
|
if cursor.fetchall() == []:
|
||||||
cursor.execute("SELECT InitSpatialMetaData(1)")
|
if self.ops.spatial_version < (5,):
|
||||||
|
cursor.execute('SELECT InitSpatialMetaData(1)')
|
||||||
|
else:
|
||||||
|
cursor.execute('SELECT InitSpatialMetaDataFull(1)')
|
||||||
|
|
|
@ -11,7 +11,7 @@ class DatabaseFeatures(BaseSpatialFeatures, SQLiteDatabaseFeatures):
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def supports_area_geodetic(self):
|
def supports_area_geodetic(self):
|
||||||
return bool(self.connection.ops.lwgeom_version())
|
return bool(self.connection.ops.geom_lib_version())
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def django_test_skips(self):
|
def django_test_skips(self):
|
||||||
|
|
|
@ -81,7 +81,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
|
||||||
@cached_property
|
@cached_property
|
||||||
def unsupported_functions(self):
|
def unsupported_functions(self):
|
||||||
unsupported = {'BoundingCircle', 'GeometryDistance', 'MemSize'}
|
unsupported = {'BoundingCircle', 'GeometryDistance', 'MemSize'}
|
||||||
if not self.lwgeom_version():
|
if not self.geom_lib_version():
|
||||||
unsupported |= {'Azimuth', 'GeoHash', 'MakeValid'}
|
unsupported |= {'Azimuth', 'GeoHash', 'MakeValid'}
|
||||||
return unsupported
|
return unsupported
|
||||||
|
|
||||||
|
@ -167,6 +167,20 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
|
||||||
"""Return the version of LWGEOM library used by SpatiaLite."""
|
"""Return the version of LWGEOM library used by SpatiaLite."""
|
||||||
return self._get_spatialite_func('lwgeom_version()')
|
return self._get_spatialite_func('lwgeom_version()')
|
||||||
|
|
||||||
|
def rttopo_version(self):
|
||||||
|
"""Return the version of RTTOPO library used by SpatiaLite."""
|
||||||
|
return self._get_spatialite_func('rttopo_version()')
|
||||||
|
|
||||||
|
def geom_lib_version(self):
|
||||||
|
"""
|
||||||
|
Return the version of the version-dependant geom library used by
|
||||||
|
SpatiaLite.
|
||||||
|
"""
|
||||||
|
if self.spatial_version >= (5,):
|
||||||
|
return self.rttopo_version()
|
||||||
|
else:
|
||||||
|
return self.lwgeom_version()
|
||||||
|
|
||||||
def spatialite_version(self):
|
def spatialite_version(self):
|
||||||
"Return the SpatiaLite library version as a string."
|
"Return the SpatiaLite library version as a string."
|
||||||
return self._get_spatialite_func('spatialite_version()')
|
return self._get_spatialite_func('spatialite_version()')
|
||||||
|
|
|
@ -344,9 +344,9 @@ functions are available on each spatial backend.
|
||||||
|
|
||||||
.. currentmodule:: django.contrib.gis.db.models.functions
|
.. currentmodule:: django.contrib.gis.db.models.functions
|
||||||
|
|
||||||
==================================== ======= ============== ============ =========== ==========
|
==================================== ======= ============== ============ =========== =================
|
||||||
Function PostGIS Oracle MariaDB MySQL SpatiaLite
|
Function PostGIS Oracle MariaDB MySQL SpatiaLite
|
||||||
==================================== ======= ============== ============ =========== ==========
|
==================================== ======= ============== ============ =========== =================
|
||||||
:class:`Area` X X X X X
|
:class:`Area` X X X X X
|
||||||
:class:`AsGeoJSON` X X X (≥ 10.2.4) X (≥ 5.7.5) X
|
:class:`AsGeoJSON` X X X (≥ 10.2.4) X (≥ 5.7.5) X
|
||||||
:class:`AsGML` X X X
|
:class:`AsGML` X X X
|
||||||
|
@ -354,19 +354,19 @@ Function PostGIS Oracle MariaDB MySQL
|
||||||
:class:`AsSVG` X X
|
:class:`AsSVG` X X
|
||||||
:class:`AsWKB` X X X X X
|
:class:`AsWKB` X X X X X
|
||||||
:class:`AsWKT` X X X X X
|
:class:`AsWKT` X X X X X
|
||||||
:class:`Azimuth` X X (LWGEOM)
|
:class:`Azimuth` X X (LWGEOM/RTTOPO)
|
||||||
:class:`BoundingCircle` X X
|
:class:`BoundingCircle` X X
|
||||||
:class:`Centroid` X X X X X
|
:class:`Centroid` X X X X X
|
||||||
:class:`Difference` X X X X X
|
:class:`Difference` X X X X X
|
||||||
:class:`Distance` X X X X X
|
:class:`Distance` X X X X X
|
||||||
:class:`Envelope` X X X X X
|
:class:`Envelope` X X X X X
|
||||||
:class:`ForcePolygonCW` X X
|
:class:`ForcePolygonCW` X X
|
||||||
:class:`GeoHash` X X (≥ 5.7.5) X (LWGEOM)
|
:class:`GeoHash` X X (≥ 5.7.5) X (LWGEOM/RTTOPO)
|
||||||
:class:`Intersection` X X X X X
|
:class:`Intersection` X X X X X
|
||||||
:class:`IsValid` X X X (≥ 5.7.5) X
|
:class:`IsValid` X X X (≥ 5.7.5) X
|
||||||
:class:`Length` X X X X X
|
:class:`Length` X X X X X
|
||||||
:class:`LineLocatePoint` X X
|
:class:`LineLocatePoint` X X
|
||||||
:class:`MakeValid` X X (LWGEOM)
|
:class:`MakeValid` X X (LWGEOM/RTTOPO)
|
||||||
:class:`MemSize` X
|
:class:`MemSize` X
|
||||||
:class:`NumGeometries` X X X X X
|
:class:`NumGeometries` X X X X X
|
||||||
:class:`NumPoints` X X X X X
|
:class:`NumPoints` X X X X X
|
||||||
|
@ -379,7 +379,7 @@ Function PostGIS Oracle MariaDB MySQL
|
||||||
:class:`Transform` X X X
|
:class:`Transform` X X X
|
||||||
:class:`Translate` X X
|
:class:`Translate` X X
|
||||||
:class:`Union` X X X X X
|
:class:`Union` X X X X X
|
||||||
==================================== ======= ============== ============ =========== ==========
|
==================================== ======= ============== ============ =========== =================
|
||||||
|
|
||||||
Aggregate Functions
|
Aggregate Functions
|
||||||
-------------------
|
-------------------
|
||||||
|
|
|
@ -44,7 +44,7 @@ Oracle, `PostGIS <https://postgis.net/docs/ST_Area.html>`__, SpatiaLite
|
||||||
Accepts a single geographic field or expression and returns the area of the
|
Accepts a single geographic field or expression and returns the area of the
|
||||||
field as an :class:`~django.contrib.gis.measure.Area` measure.
|
field as an :class:`~django.contrib.gis.measure.Area` measure.
|
||||||
|
|
||||||
MySQL and SpatiaLite without LWGEOM don't support area calculations on
|
MySQL and SpatiaLite without LWGEOM/RTTOPO don't support area calculations on
|
||||||
geographic SRSes.
|
geographic SRSes.
|
||||||
|
|
||||||
``AsGeoJSON``
|
``AsGeoJSON``
|
||||||
|
@ -208,7 +208,7 @@ __ https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry
|
||||||
.. class:: Azimuth(point_a, point_b, **extra)
|
.. class:: Azimuth(point_a, point_b, **extra)
|
||||||
|
|
||||||
*Availability*: `PostGIS <https://postgis.net/docs/ST_Azimuth.html>`__,
|
*Availability*: `PostGIS <https://postgis.net/docs/ST_Azimuth.html>`__,
|
||||||
SpatiaLite (LWGEOM)
|
SpatiaLite (LWGEOM/RTTOPO)
|
||||||
|
|
||||||
Returns the azimuth in radians of the segment defined by the given point
|
Returns the azimuth in radians of the segment defined by the given point
|
||||||
geometries, or ``None`` if the two points are coincident. The azimuth is angle
|
geometries, or ``None`` if the two points are coincident. The azimuth is angle
|
||||||
|
@ -334,7 +334,8 @@ are returned unchanged.
|
||||||
|
|
||||||
*Availability*: `MySQL
|
*Availability*: `MySQL
|
||||||
<https://dev.mysql.com/doc/refman/en/spatial-geohash-functions.html#function_st-geohash>`__ (≥ 5.7.5),
|
<https://dev.mysql.com/doc/refman/en/spatial-geohash-functions.html#function_st-geohash>`__ (≥ 5.7.5),
|
||||||
`PostGIS <https://postgis.net/docs/ST_GeoHash.html>`__, SpatiaLite (LWGEOM)
|
`PostGIS <https://postgis.net/docs/ST_GeoHash.html>`__, SpatiaLite
|
||||||
|
(LWGEOM/RTTOPO)
|
||||||
|
|
||||||
Accepts a single geographic field or expression and returns a `GeoHash`__
|
Accepts a single geographic field or expression and returns a `GeoHash`__
|
||||||
representation of the geometry.
|
representation of the geometry.
|
||||||
|
@ -416,7 +417,7 @@ Returns a float between 0 and 1 representing the location of the closest point o
|
||||||
.. class:: MakeValid(expr)
|
.. class:: MakeValid(expr)
|
||||||
|
|
||||||
*Availability*: `PostGIS <https://postgis.net/docs/ST_MakeValid.html>`__,
|
*Availability*: `PostGIS <https://postgis.net/docs/ST_MakeValid.html>`__,
|
||||||
SpatiaLite (LWGEOM)
|
SpatiaLite (LWGEOM/RTTOPO)
|
||||||
|
|
||||||
Accepts a geographic field or expression and attempts to convert the value into
|
Accepts a geographic field or expression and attempts to convert the value into
|
||||||
a valid geometry without losing any of the input vertices. Geometries that are
|
a valid geometry without losing any of the input vertices. Geometries that are
|
||||||
|
|
|
@ -13,7 +13,7 @@ Program Description Required
|
||||||
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 3.2, 3.1, 3.0, 2.4, 2.3, 2.2, 2.1
|
:doc:`GDAL <../gdal>` Geospatial Data Abstraction Library Yes 3.2, 3.1, 3.0, 2.4, 2.3, 2.2, 2.1
|
||||||
: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.0, 2.5, 2.4
|
`PostGIS`__ Spatial extensions for PostgreSQL Yes (PostgreSQL only) 3.0, 2.5, 2.4
|
||||||
`SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 4.3
|
`SpatiaLite`__ Spatial extensions for SQLite Yes (SQLite only) 5.0, 4.3
|
||||||
======================== ==================================== ================================ =================================
|
======================== ==================================== ================================ =================================
|
||||||
|
|
||||||
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
|
||||||
|
@ -36,6 +36,7 @@ totally fine with GeoDjango. Your mileage may vary.
|
||||||
PostGIS 2.5.0 2018-09-23
|
PostGIS 2.5.0 2018-09-23
|
||||||
PostGIS 3.0.0 2019-10-20
|
PostGIS 3.0.0 2019-10-20
|
||||||
SpatiaLite 4.3.0 2015-09-07
|
SpatiaLite 4.3.0 2015-09-07
|
||||||
|
SpatiaLite 5.0.0 2020-08-23
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
|
|
@ -100,7 +100,7 @@ Minor features
|
||||||
:mod:`django.contrib.gis`
|
:mod:`django.contrib.gis`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
* ...
|
* Added support for SpatiaLite 5.
|
||||||
|
|
||||||
:mod:`django.contrib.messages`
|
:mod:`django.contrib.messages`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -367,16 +367,12 @@ class DistanceFunctionsTests(FuncTestMixin, TestCase):
|
||||||
dist2 = SouthTexasCityFt.objects.annotate(distance=Distance('point', lagrange)).order_by('id')
|
dist2 = SouthTexasCityFt.objects.annotate(distance=Distance('point', lagrange)).order_by('id')
|
||||||
dist_qs = [dist1, dist2]
|
dist_qs = [dist1, dist2]
|
||||||
|
|
||||||
# Original query done on PostGIS, have to adjust AlmostEqual tolerance
|
|
||||||
# for Oracle.
|
|
||||||
tol = 2 if connection.ops.oracle else 5
|
|
||||||
|
|
||||||
# Ensuring expected distances are returned for each distance queryset.
|
# Ensuring expected distances are returned for each distance queryset.
|
||||||
for qs in dist_qs:
|
for qs in dist_qs:
|
||||||
for i, c in enumerate(qs):
|
for i, c in enumerate(qs):
|
||||||
with self.subTest(c=c):
|
with self.subTest(c=c):
|
||||||
self.assertAlmostEqual(m_distances[i], c.distance.m, tol)
|
self.assertAlmostEqual(m_distances[i], c.distance.m, -1)
|
||||||
self.assertAlmostEqual(ft_distances[i], c.distance.survey_ft, tol)
|
self.assertAlmostEqual(ft_distances[i], c.distance.survey_ft, -1)
|
||||||
|
|
||||||
@skipUnlessDBFeature("has_Distance_function", "supports_distance_geodetic")
|
@skipUnlessDBFeature("has_Distance_function", "supports_distance_geodetic")
|
||||||
def test_distance_geodetic(self):
|
def test_distance_geodetic(self):
|
||||||
|
|
|
@ -183,7 +183,11 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
def test_azimuth(self):
|
def test_azimuth(self):
|
||||||
# Returns the azimuth in radians.
|
# Returns the azimuth in radians.
|
||||||
azimuth_expr = functions.Azimuth(Point(0, 0, srid=4326), Point(1, 1, srid=4326))
|
azimuth_expr = functions.Azimuth(Point(0, 0, srid=4326), Point(1, 1, srid=4326))
|
||||||
self.assertAlmostEqual(City.objects.annotate(azimuth=azimuth_expr).first().azimuth, math.pi / 4)
|
self.assertAlmostEqual(
|
||||||
|
City.objects.annotate(azimuth=azimuth_expr).first().azimuth,
|
||||||
|
math.pi / 4,
|
||||||
|
places=2,
|
||||||
|
)
|
||||||
# Returns None if the two points are coincident.
|
# Returns None if the two points are coincident.
|
||||||
azimuth_expr = functions.Azimuth(Point(0, 0, srid=4326), Point(0, 0, srid=4326))
|
azimuth_expr = functions.Azimuth(Point(0, 0, srid=4326), Point(0, 0, srid=4326))
|
||||||
self.assertIsNone(City.objects.annotate(azimuth=azimuth_expr).first().azimuth)
|
self.assertIsNone(City.objects.annotate(azimuth=azimuth_expr).first().azimuth)
|
||||||
|
|
|
@ -111,9 +111,12 @@ class GeographyFunctionTests(FuncTestMixin, TestCase):
|
||||||
if connection.ops.oracle:
|
if connection.ops.oracle:
|
||||||
ref_dists = [0, 4899.68, 8081.30, 9115.15]
|
ref_dists = [0, 4899.68, 8081.30, 9115.15]
|
||||||
elif connection.ops.spatialite:
|
elif connection.ops.spatialite:
|
||||||
# SpatiaLite returns non-zero distance for polygons and points
|
if connection.ops.spatial_version < (5,):
|
||||||
|
# SpatiaLite < 5 returns non-zero distance for polygons and points
|
||||||
# covered by that polygon.
|
# covered by that polygon.
|
||||||
ref_dists = [326.61, 4899.68, 8081.30, 9115.15]
|
ref_dists = [326.61, 4899.68, 8081.30, 9115.15]
|
||||||
|
else:
|
||||||
|
ref_dists = [0, 4899.68, 8081.30, 9115.15]
|
||||||
else:
|
else:
|
||||||
ref_dists = [0, 4891.20, 8071.64, 9123.95]
|
ref_dists = [0, 4891.20, 8071.64, 9123.95]
|
||||||
htown = City.objects.get(name='Houston')
|
htown = City.objects.get(name='Houston')
|
||||||
|
|
Loading…
Reference in New Issue