mirror of
https://github.com/django/django.git
synced 2025-06-05 11:39:13 +00:00
Refs #31014 -- Added FromWKB and FromWKT GIS database functions.
Co-authored-by: Ondřej Böhm <ondrej.bohm@firma.seznam.cz> Co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com> Co-authored-by: Sergey Fedoseev <fedoseev.sergey@gmail.com>
This commit is contained in:
parent
72efd840a8
commit
552384fa97
@ -45,6 +45,8 @@ class BaseSpatialOperations:
|
|||||||
"Difference",
|
"Difference",
|
||||||
"Distance",
|
"Distance",
|
||||||
"Envelope",
|
"Envelope",
|
||||||
|
"FromWKB",
|
||||||
|
"FromWKT",
|
||||||
"GeoHash",
|
"GeoHash",
|
||||||
"GeometryDistance",
|
"GeometryDistance",
|
||||||
"Intersection",
|
"Intersection",
|
||||||
|
@ -62,6 +62,11 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
|
|||||||
models.Union,
|
models.Union,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
function_names = {
|
||||||
|
"FromWKB": "ST_GeomFromWKB",
|
||||||
|
"FromWKT": "ST_GeomFromText",
|
||||||
|
}
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def unsupported_functions(self):
|
def unsupported_functions(self):
|
||||||
unsupported = {
|
unsupported = {
|
||||||
|
@ -76,6 +76,8 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
|||||||
"Difference": "SDO_GEOM.SDO_DIFFERENCE",
|
"Difference": "SDO_GEOM.SDO_DIFFERENCE",
|
||||||
"Distance": "SDO_GEOM.SDO_DISTANCE",
|
"Distance": "SDO_GEOM.SDO_DISTANCE",
|
||||||
"Envelope": "SDO_GEOM_MBR",
|
"Envelope": "SDO_GEOM_MBR",
|
||||||
|
"FromWKB": "SDO_UTIL.FROM_WKBGEOMETRY",
|
||||||
|
"FromWKT": "SDO_UTIL.FROM_WKTGEOMETRY",
|
||||||
"Intersection": "SDO_GEOM.SDO_INTERSECTION",
|
"Intersection": "SDO_GEOM.SDO_INTERSECTION",
|
||||||
"IsValid": "SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT",
|
"IsValid": "SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT",
|
||||||
"Length": "SDO_GEOM.SDO_LENGTH",
|
"Length": "SDO_GEOM.SDO_LENGTH",
|
||||||
|
@ -172,6 +172,8 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
|
|||||||
"AsWKB": "ST_AsBinary",
|
"AsWKB": "ST_AsBinary",
|
||||||
"AsWKT": "ST_AsText",
|
"AsWKT": "ST_AsText",
|
||||||
"BoundingCircle": "ST_MinimumBoundingCircle",
|
"BoundingCircle": "ST_MinimumBoundingCircle",
|
||||||
|
"FromWKB": "ST_GeomFromWKB",
|
||||||
|
"FromWKT": "ST_GeomFromText",
|
||||||
"NumPoints": "ST_NPoints",
|
"NumPoints": "ST_NPoints",
|
||||||
}
|
}
|
||||||
return function_names
|
return function_names
|
||||||
|
@ -67,6 +67,8 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
|
|||||||
function_names = {
|
function_names = {
|
||||||
"AsWKB": "St_AsBinary",
|
"AsWKB": "St_AsBinary",
|
||||||
"ForcePolygonCW": "ST_ForceLHR",
|
"ForcePolygonCW": "ST_ForceLHR",
|
||||||
|
"FromWKB": "ST_GeomFromWKB",
|
||||||
|
"FromWKT": "ST_GeomFromText",
|
||||||
"Length": "ST_Length",
|
"Length": "ST_Length",
|
||||||
"LineLocatePoint": "ST_Line_Locate_Point",
|
"LineLocatePoint": "ST_Line_Locate_Point",
|
||||||
"NumPoints": "ST_NPoints",
|
"NumPoints": "ST_NPoints",
|
||||||
|
@ -69,6 +69,8 @@ class GeoFuncMixin:
|
|||||||
|
|
||||||
def resolve_expression(self, *args, **kwargs):
|
def resolve_expression(self, *args, **kwargs):
|
||||||
res = super().resolve_expression(*args, **kwargs)
|
res = super().resolve_expression(*args, **kwargs)
|
||||||
|
if not self.geom_param_pos:
|
||||||
|
return res
|
||||||
|
|
||||||
# Ensure that expressions are geometric.
|
# Ensure that expressions are geometric.
|
||||||
source_fields = res.get_source_fields()
|
source_fields = res.get_source_fields()
|
||||||
@ -351,6 +353,18 @@ class ForcePolygonCW(GeomOutputGeoFunc):
|
|||||||
arity = 1
|
arity = 1
|
||||||
|
|
||||||
|
|
||||||
|
class FromWKB(GeoFunc):
|
||||||
|
output_field = GeometryField(srid=0)
|
||||||
|
arity = 1
|
||||||
|
geom_param_pos = ()
|
||||||
|
|
||||||
|
|
||||||
|
class FromWKT(GeoFunc):
|
||||||
|
output_field = GeometryField(srid=0)
|
||||||
|
arity = 1
|
||||||
|
geom_param_pos = ()
|
||||||
|
|
||||||
|
|
||||||
class GeoHash(GeoFunc):
|
class GeoHash(GeoFunc):
|
||||||
output_field = TextField()
|
output_field = TextField()
|
||||||
|
|
||||||
|
@ -360,6 +360,8 @@ Function PostGIS Oracle MariaDB MySQL
|
|||||||
: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:`FromWKB` X X X X X
|
||||||
|
:class:`FromWKT` X X X X X
|
||||||
:class:`GeoHash` X X X (LWGEOM/RTTOPO)
|
:class:`GeoHash` X X X (LWGEOM/RTTOPO)
|
||||||
:class:`Intersection` X X X X X
|
:class:`Intersection` X X X X X
|
||||||
:class:`IsEmpty` X
|
:class:`IsEmpty` X
|
||||||
|
@ -20,17 +20,17 @@ get a ``NotImplementedError`` exception.
|
|||||||
|
|
||||||
Function's summary:
|
Function's summary:
|
||||||
|
|
||||||
========================= ======================== ====================== ======================= ================== =====================
|
========================= ======================== ====================== ======================= ================== ================== ======================
|
||||||
Measurement Relationships Operations Editors Output format Miscellaneous
|
Measurement Relationships Operations Editors Input format Output format Miscellaneous
|
||||||
========================= ======================== ====================== ======================= ================== =====================
|
========================= ======================== ====================== ======================= ================== ================== ======================
|
||||||
:class:`Area` :class:`Azimuth` :class:`Difference` :class:`ForcePolygonCW` :class:`AsGeoJSON` :class:`IsEmpty`
|
:class:`Area` :class:`Azimuth` :class:`Difference` :class:`ForcePolygonCW` :class:`AsGeoJSON` :class:`IsEmpty`
|
||||||
:class:`Distance` :class:`BoundingCircle` :class:`Intersection` :class:`MakeValid` :class:`AsGML` :class:`IsValid`
|
:class:`Distance` :class:`BoundingCircle` :class:`Intersection` :class:`MakeValid` :class:`AsGML` :class:`IsValid`
|
||||||
:class:`GeometryDistance` :class:`Centroid` :class:`SymDifference` :class:`Reverse` :class:`AsKML` :class:`MemSize`
|
:class:`GeometryDistance` :class:`Centroid` :class:`SymDifference` :class:`Reverse` :class:`AsKML` :class:`MemSize`
|
||||||
:class:`Length` :class:`Envelope` :class:`Union` :class:`Scale` :class:`AsSVG` :class:`NumGeometries`
|
:class:`Length` :class:`Envelope` :class:`Union` :class:`Scale` :class:`AsSVG` :class:`NumGeometries`
|
||||||
:class:`Perimeter` :class:`LineLocatePoint` :class:`SnapToGrid` :class:`AsWKB` :class:`NumPoints`
|
:class:`Perimeter` :class:`LineLocatePoint` :class:`SnapToGrid` :class:`FromWKB` :class:`AsWKB` :class:`NumPoints`
|
||||||
.. :class:`PointOnSurface` :class:`Transform` :class:`AsWKT`
|
:class:`PointOnSurface` :class:`Transform` :class:`FromWKT` :class:`AsWKT`
|
||||||
.. :class:`Translate` :class:`GeoHash`
|
:class:`Translate` :class:`GeoHash`
|
||||||
========================= ======================== ====================== ======================= ================== =====================
|
========================= ======================== ====================== ======================= ================== ================== ======================
|
||||||
|
|
||||||
``Area``
|
``Area``
|
||||||
========
|
========
|
||||||
@ -174,15 +174,13 @@ __ https://www.w3.org/Graphics/SVG/
|
|||||||
Oracle, `PostGIS <https://postgis.net/docs/ST_AsBinary.html>`__, SpatiaLite
|
Oracle, `PostGIS <https://postgis.net/docs/ST_AsBinary.html>`__, SpatiaLite
|
||||||
|
|
||||||
Accepts a single geographic field or expression and returns a `Well-known
|
Accepts a single geographic field or expression and returns a `Well-known
|
||||||
binary (WKB)`__ representation of the geometry.
|
binary (WKB)`_ representation of the geometry.
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
>>> bytes(City.objects.annotate(wkb=AsWKB('point')).get(name='Chelyabinsk').wkb)
|
>>> bytes(City.objects.annotate(wkb=AsWKB('point')).get(name='Chelyabinsk').wkb)
|
||||||
b'\x01\x01\x00\x00\x00]3\xf9f\x9b\x91K@\x00X\x1d9\xd2\xb9N@'
|
b'\x01\x01\x00\x00\x00]3\xf9f\x9b\x91K@\x00X\x1d9\xd2\xb9N@'
|
||||||
|
|
||||||
__ https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry#Well-known_binary
|
|
||||||
|
|
||||||
``AsWKT``
|
``AsWKT``
|
||||||
=========
|
=========
|
||||||
|
|
||||||
@ -193,15 +191,13 @@ __ https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry#Well
|
|||||||
Oracle, `PostGIS <https://postgis.net/docs/ST_AsText.html>`__, SpatiaLite
|
Oracle, `PostGIS <https://postgis.net/docs/ST_AsText.html>`__, SpatiaLite
|
||||||
|
|
||||||
Accepts a single geographic field or expression and returns a `Well-known text
|
Accepts a single geographic field or expression and returns a `Well-known text
|
||||||
(WKT)`__ representation of the geometry.
|
(WKT)`_ representation of the geometry.
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
>>> City.objects.annotate(wkt=AsWKT('point')).get(name='Chelyabinsk').wkt
|
>>> City.objects.annotate(wkt=AsWKT('point')).get(name='Chelyabinsk').wkt
|
||||||
'POINT (55.137555 61.451728)'
|
'POINT (55.137555 61.451728)'
|
||||||
|
|
||||||
__ https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry
|
|
||||||
|
|
||||||
``Azimuth``
|
``Azimuth``
|
||||||
===========
|
===========
|
||||||
|
|
||||||
@ -327,6 +323,32 @@ of the polygon/multipolygon in which all exterior rings are oriented clockwise
|
|||||||
and all interior rings are oriented counterclockwise. Non-polygonal geometries
|
and all interior rings are oriented counterclockwise. Non-polygonal geometries
|
||||||
are returned unchanged.
|
are returned unchanged.
|
||||||
|
|
||||||
|
``FromWKB``
|
||||||
|
===========
|
||||||
|
|
||||||
|
.. versionadded:: 4.2
|
||||||
|
|
||||||
|
.. class:: FromWKB(expression, **extra)
|
||||||
|
|
||||||
|
*Availability*: MariaDB, `MySQL
|
||||||
|
<https://dev.mysql.com/doc/refman/en/gis-wkb-functions.html#function_st-geomfromwkb>`__,
|
||||||
|
Oracle, `PostGIS <https://postgis.net/docs/ST_GeomFromWKB.html>`__, SpatiaLite
|
||||||
|
|
||||||
|
Creates geometry from `Well-known binary (WKB)`_ representation.
|
||||||
|
|
||||||
|
``FromWKT``
|
||||||
|
===========
|
||||||
|
|
||||||
|
.. versionadded:: 4.2
|
||||||
|
|
||||||
|
.. class:: FromWKT(expression, **extra)
|
||||||
|
|
||||||
|
*Availability*: MariaDB, `MySQL
|
||||||
|
<https://dev.mysql.com/doc/refman/en/gis-wkt-functions.html#function_st-geomfromtext>`__,
|
||||||
|
Oracle, `PostGIS <https://postgis.net/docs/ST_GeomFromText.html>`__, SpatiaLite
|
||||||
|
|
||||||
|
Creates geometry from `Well-known text (WKT)`_ representation.
|
||||||
|
|
||||||
``GeoHash``
|
``GeoHash``
|
||||||
===========
|
===========
|
||||||
|
|
||||||
@ -596,3 +618,6 @@ parameters.
|
|||||||
|
|
||||||
Accepts two geographic fields or expressions and returns the union of both
|
Accepts two geographic fields or expressions and returns the union of both
|
||||||
geometries.
|
geometries.
|
||||||
|
|
||||||
|
.. _`Well-known binary (WKB)`: https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry#Well-known_binary
|
||||||
|
.. _`Well-known text (WKT)`: https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry
|
||||||
|
@ -167,6 +167,11 @@ Minor features
|
|||||||
:class:`IsEmpty() <django.contrib.gis.db.models.functions.IsEmpty>`
|
:class:`IsEmpty() <django.contrib.gis.db.models.functions.IsEmpty>`
|
||||||
expression allow filtering empty geometries on PostGIS.
|
expression allow filtering empty geometries on PostGIS.
|
||||||
|
|
||||||
|
* The new :class:`FromWKB() <django.contrib.gis.db.models.functions.FromWKB>`
|
||||||
|
and :class:`FromWKT() <django.contrib.gis.db.models.functions.FromWKT>`
|
||||||
|
functions allow creating geometries from Well-known binary (WKB) and
|
||||||
|
Well-known text (WKT) representations.
|
||||||
|
|
||||||
:mod:`django.contrib.messages`
|
:mod:`django.contrib.messages`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -326,6 +326,24 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
|||||||
).get(name="Foo")
|
).get(name="Foo")
|
||||||
self.assertEqual(rhr_rings, st.force_polygon_cw.coords)
|
self.assertEqual(rhr_rings, st.force_polygon_cw.coords)
|
||||||
|
|
||||||
|
@skipUnlessDBFeature("has_FromWKB_function")
|
||||||
|
def test_fromwkb(self):
|
||||||
|
g = Point(56.811078, 60.608647)
|
||||||
|
g2 = City.objects.values_list(
|
||||||
|
functions.FromWKB(Value(g.wkb.tobytes())),
|
||||||
|
flat=True,
|
||||||
|
)[0]
|
||||||
|
self.assertIs(g.equals_exact(g2, 0.00001), True)
|
||||||
|
|
||||||
|
@skipUnlessDBFeature("has_FromWKT_function")
|
||||||
|
def test_fromwkt(self):
|
||||||
|
g = Point(56.811078, 60.608647)
|
||||||
|
g2 = City.objects.values_list(
|
||||||
|
functions.FromWKT(Value(g.wkt)),
|
||||||
|
flat=True,
|
||||||
|
)[0]
|
||||||
|
self.assertIs(g.equals_exact(g2, 0.00001), True)
|
||||||
|
|
||||||
@skipUnlessDBFeature("has_GeoHash_function")
|
@skipUnlessDBFeature("has_GeoHash_function")
|
||||||
def test_geohash(self):
|
def test_geohash(self):
|
||||||
# Reference query:
|
# Reference query:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user