Fixed #28738 -- Added the GeometryDistance function.
This commit is contained in:
parent
638d5ea375
commit
0193bf874f
1
AUTHORS
1
AUTHORS
|
@ -282,6 +282,7 @@ answer newbie questions, and generally made Django that much better:
|
|||
Florian Apolloner <florian@apolloner.eu>
|
||||
Florian Moussous <florian.moussous@gmail.com>
|
||||
Francisco Albarran Cristobal <pahko.xd@gmail.com>
|
||||
Francisco Couzo <franciscouzo@gmail.com>
|
||||
François Freitag <mail@franek.fr>
|
||||
Frank Tegtmeyer <fte@fte.to>
|
||||
Frank Wierzbicki
|
||||
|
|
|
@ -40,10 +40,10 @@ class BaseSpatialOperations:
|
|||
unsupported_functions = {
|
||||
'Area', 'AsGeoJSON', 'AsGML', 'AsKML', 'AsSVG', 'Azimuth',
|
||||
'BoundingCircle', 'Centroid', 'Difference', 'Distance', 'Envelope',
|
||||
'GeoHash', 'Intersection', 'IsValid', 'Length', 'LineLocatePoint',
|
||||
'MakeValid', 'MemSize', 'NumGeometries', 'NumPoints', 'Perimeter',
|
||||
'PointOnSurface', 'Reverse', 'Scale', 'SnapToGrid', 'SymDifference',
|
||||
'Transform', 'Translate', 'Union',
|
||||
'GeoHash', 'GeometryDistance', 'Intersection', 'IsValid', 'Length',
|
||||
'LineLocatePoint', 'MakeValid', 'MemSize', 'NumGeometries',
|
||||
'NumPoints', 'Perimeter', 'PointOnSurface', 'Reverse', 'Scale',
|
||||
'SnapToGrid', 'SymDifference', 'Transform', 'Translate', 'Union',
|
||||
}
|
||||
|
||||
# Constructors
|
||||
|
|
|
@ -54,9 +54,9 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
|
|||
def unsupported_functions(self):
|
||||
unsupported = {
|
||||
'AsGML', 'AsKML', 'AsSVG', 'Azimuth', 'BoundingCircle',
|
||||
'ForcePolygonCW', 'LineLocatePoint', 'MakeValid', 'MemSize',
|
||||
'Perimeter', 'PointOnSurface', 'Reverse', 'Scale', 'SnapToGrid',
|
||||
'Transform', 'Translate',
|
||||
'ForcePolygonCW', 'GeometryDistance', 'LineLocatePoint',
|
||||
'MakeValid', 'MemSize', 'Perimeter', 'PointOnSurface', 'Reverse',
|
||||
'Scale', 'SnapToGrid', 'Transform', 'Translate',
|
||||
}
|
||||
if self.connection.mysql_is_mariadb:
|
||||
unsupported.update({'GeoHash', 'IsValid'})
|
||||
|
|
|
@ -107,8 +107,8 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
|||
|
||||
unsupported_functions = {
|
||||
'AsGeoJSON', 'AsKML', 'AsSVG', 'Azimuth', 'ForcePolygonCW', 'GeoHash',
|
||||
'LineLocatePoint', 'MakeValid', 'MemSize', 'Scale', 'SnapToGrid',
|
||||
'Translate',
|
||||
'GeometryDistance', 'LineLocatePoint', 'MakeValid', 'MemSize',
|
||||
'Scale', 'SnapToGrid', 'Translate',
|
||||
}
|
||||
|
||||
def geo_quote_name(self, name):
|
||||
|
|
|
@ -79,7 +79,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
|
|||
|
||||
@cached_property
|
||||
def unsupported_functions(self):
|
||||
unsupported = {'BoundingCircle', 'MemSize'}
|
||||
unsupported = {'BoundingCircle', 'GeometryDistance', 'MemSize'}
|
||||
if not self.lwgeom_version():
|
||||
unsupported |= {'Azimuth', 'GeoHash', 'IsValid', 'MakeValid'}
|
||||
return unsupported
|
||||
|
|
|
@ -48,7 +48,7 @@ class GeoFuncMixin:
|
|||
return self.source_expressions[self.geom_param_pos[0]].field
|
||||
|
||||
def as_sql(self, compiler, connection, function=None, **extra_context):
|
||||
if not self.function and not function:
|
||||
if self.function is None and function is None:
|
||||
function = connection.ops.spatial_function_name(self.name)
|
||||
return super().as_sql(compiler, connection, function=function, **extra_context)
|
||||
|
||||
|
@ -299,6 +299,14 @@ class GeoHash(GeoFunc):
|
|||
return clone.as_sql(compiler, connection, **extra_context)
|
||||
|
||||
|
||||
class GeometryDistance(GeoFunc):
|
||||
output_field = FloatField()
|
||||
arity = 2
|
||||
function = ''
|
||||
arg_joiner = ' <-> '
|
||||
geom_param_pos = (0, 1)
|
||||
|
||||
|
||||
class Intersection(OracleToleranceMixin, GeomOutputGeoFunc):
|
||||
arity = 2
|
||||
geom_param_pos = (0, 1)
|
||||
|
|
|
@ -20,17 +20,17 @@ get a ``NotImplementedError`` exception.
|
|||
|
||||
Function's summary:
|
||||
|
||||
================== ======================== ====================== ======================= ================== =====================
|
||||
Measurement Relationships Operations Editors Output format Miscellaneous
|
||||
================== ======================== ====================== ======================= ================== =====================
|
||||
:class:`Area` :class:`Azimuth` :class:`Difference` :class:`ForcePolygonCW` :class:`AsGeoJSON` :class:`IsValid`
|
||||
:class:`Distance` :class:`BoundingCircle` :class:`Intersection` :class:`MakeValid` :class:`AsGML` :class:`MemSize`
|
||||
:class:`Length` :class:`Centroid` :class:`SymDifference` :class:`Reverse` :class:`AsKML` :class:`NumGeometries`
|
||||
:class:`Perimeter` :class:`Envelope` :class:`Union` :class:`Scale` :class:`AsSVG` :class:`NumPoints`
|
||||
.. :class:`LineLocatePoint` :class:`SnapToGrid` :class:`GeoHash`
|
||||
.. :class:`PointOnSurface` :class:`Transform`
|
||||
.. :class:`Translate`
|
||||
================== ======================== ====================== ======================= ================== =====================
|
||||
========================= ======================== ====================== ======================= ================== =====================
|
||||
Measurement Relationships Operations Editors Output format Miscellaneous
|
||||
========================= ======================== ====================== ======================= ================== =====================
|
||||
:class:`Area` :class:`Azimuth` :class:`Difference` :class:`ForcePolygonCW` :class:`AsGeoJSON` :class:`IsValid`
|
||||
:class:`Distance` :class:`BoundingCircle` :class:`Intersection` :class:`MakeValid` :class:`AsGML` :class:`MemSize`
|
||||
:class:`GeometryDistance` :class:`Centroid` :class:`SymDifference` :class:`Reverse` :class:`AsKML` :class:`NumGeometries`
|
||||
:class:`Length` :class:`Envelope` :class:`Union` :class:`Scale` :class:`AsSVG` :class:`NumPoints`
|
||||
:class:`Perimeter` :class:`LineLocatePoint` :class:`SnapToGrid` :class:`GeoHash`
|
||||
.. :class:`PointOnSurface` :class:`Transform`
|
||||
.. :class:`Translate`
|
||||
========================= ======================== ====================== ======================= ================== =====================
|
||||
|
||||
``Area``
|
||||
========
|
||||
|
@ -308,6 +308,19 @@ result.
|
|||
|
||||
__ https://en.wikipedia.org/wiki/Geohash
|
||||
|
||||
``GeometryDistance``
|
||||
====================
|
||||
|
||||
.. class:: GeometryDistance(expr1, expr2, **extra)
|
||||
|
||||
.. versionadded:: 3.0
|
||||
|
||||
*Availability*: `PostGIS <https://postgis.net/docs/geometry_distance_knn.html>`__
|
||||
|
||||
Accepts two geographic fields or expressions and returns the distance between
|
||||
them. When used in an :meth:`~django.db.models.query.QuerySet.order_by` clause,
|
||||
it provides index-assisted nearest-neighbor result sets.
|
||||
|
||||
``Intersection``
|
||||
================
|
||||
|
||||
|
|
|
@ -67,6 +67,9 @@ Minor features
|
|||
* Allowed MySQL spatial lookup functions to operate on real geometries.
|
||||
Previous support was limited to bounding boxes.
|
||||
|
||||
* Added the :class:`~django.contrib.gis.db.models.functions.GeometryDistance`
|
||||
function, supported on PostGIS.
|
||||
|
||||
:mod:`django.contrib.messages`
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -240,6 +240,21 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
|||
self.assertEqual(ref_hash, h1.geohash[:len(ref_hash)])
|
||||
self.assertEqual(ref_hash[:5], h2.geohash)
|
||||
|
||||
@skipUnlessDBFeature('has_GeometryDistance_function')
|
||||
def test_geometry_distance(self):
|
||||
point = Point(-90, 40, srid=4326)
|
||||
qs = City.objects.annotate(distance=functions.GeometryDistance('point', point)).order_by('distance')
|
||||
self.assertEqual([city.distance for city in qs], [
|
||||
2.99091995527296,
|
||||
5.33507274054713,
|
||||
9.33852187483721,
|
||||
9.91769193646233,
|
||||
11.556465744884,
|
||||
14.713098433352,
|
||||
34.3635252198568,
|
||||
276.987855073372,
|
||||
])
|
||||
|
||||
@skipUnlessDBFeature("has_Intersection_function")
|
||||
def test_intersection(self):
|
||||
geom = Point(5, 23, srid=4326)
|
||||
|
|
Loading…
Reference in New Issue