2
0
Эх сурвалжийг харах

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>
Mariusz Felisiak 2 жил өмнө
parent
commit
552384fa97

+ 2 - 0
django/contrib/gis/db/backends/base/operations.py

@@ -45,6 +45,8 @@ class BaseSpatialOperations:
         "Difference",
         "Distance",
         "Envelope",
+        "FromWKB",
+        "FromWKT",
         "GeoHash",
         "GeometryDistance",
         "Intersection",

+ 5 - 0
django/contrib/gis/db/backends/mysql/operations.py

@@ -62,6 +62,11 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
         models.Union,
     )
 
+    function_names = {
+        "FromWKB": "ST_GeomFromWKB",
+        "FromWKT": "ST_GeomFromText",
+    }
+
     @cached_property
     def unsupported_functions(self):
         unsupported = {

+ 2 - 0
django/contrib/gis/db/backends/oracle/operations.py

@@ -76,6 +76,8 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
         "Difference": "SDO_GEOM.SDO_DIFFERENCE",
         "Distance": "SDO_GEOM.SDO_DISTANCE",
         "Envelope": "SDO_GEOM_MBR",
+        "FromWKB": "SDO_UTIL.FROM_WKBGEOMETRY",
+        "FromWKT": "SDO_UTIL.FROM_WKTGEOMETRY",
         "Intersection": "SDO_GEOM.SDO_INTERSECTION",
         "IsValid": "SDO_GEOM.VALIDATE_GEOMETRY_WITH_CONTEXT",
         "Length": "SDO_GEOM.SDO_LENGTH",

+ 2 - 0
django/contrib/gis/db/backends/postgis/operations.py

@@ -172,6 +172,8 @@ class PostGISOperations(BaseSpatialOperations, DatabaseOperations):
             "AsWKB": "ST_AsBinary",
             "AsWKT": "ST_AsText",
             "BoundingCircle": "ST_MinimumBoundingCircle",
+            "FromWKB": "ST_GeomFromWKB",
+            "FromWKT": "ST_GeomFromText",
             "NumPoints": "ST_NPoints",
         }
         return function_names

+ 2 - 0
django/contrib/gis/db/backends/spatialite/operations.py

@@ -67,6 +67,8 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
     function_names = {
         "AsWKB": "St_AsBinary",
         "ForcePolygonCW": "ST_ForceLHR",
+        "FromWKB": "ST_GeomFromWKB",
+        "FromWKT": "ST_GeomFromText",
         "Length": "ST_Length",
         "LineLocatePoint": "ST_Line_Locate_Point",
         "NumPoints": "ST_NPoints",

+ 14 - 0
django/contrib/gis/db/models/functions.py

@@ -69,6 +69,8 @@ class GeoFuncMixin:
 
     def resolve_expression(self, *args, **kwargs):
         res = super().resolve_expression(*args, **kwargs)
+        if not self.geom_param_pos:
+            return res
 
         # Ensure that expressions are geometric.
         source_fields = res.get_source_fields()
@@ -351,6 +353,18 @@ class ForcePolygonCW(GeomOutputGeoFunc):
     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):
     output_field = TextField()
 

+ 2 - 0
docs/ref/contrib/gis/db-api.txt

@@ -360,6 +360,8 @@ Function                              PostGIS  Oracle         MariaDB      MySQL
 :class:`Distance`                     X        X              X            X           X
 :class:`Envelope`                     X        X              X            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:`Intersection`                 X        X              X            X           X
 :class:`IsEmpty`                      X

+ 42 - 17
docs/ref/contrib/gis/functions.txt

@@ -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:`IsEmpty`
-: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:`Length`            :class:`Envelope`         :class:`Union`          :class:`Scale`           :class:`AsSVG`      :class:`NumGeometries`
-:class:`Perimeter`         :class:`LineLocatePoint`                          :class:`SnapToGrid`      :class:`AsWKB`      :class:`NumPoints`
-..                         :class:`PointOnSurface`                           :class:`Transform`       :class:`AsWKT`
-..                                                                           :class:`Translate`       :class:`GeoHash`
-=========================  ========================  ======================  =======================  ==================  =====================
+=========================  ========================  ======================  =======================  ==================  ==================  ======================
+Measurement                Relationships             Operations              Editors                  Input format        Output format       Miscellaneous
+=========================  ========================  ======================  =======================  ==================  ==================  ======================
+: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:`GeometryDistance`  :class:`Centroid`         :class:`SymDifference`  :class:`Reverse`                             :class:`AsKML`      :class:`MemSize`
+:class:`Length`            :class:`Envelope`         :class:`Union`          :class:`Scale`                               :class:`AsSVG`      :class:`NumGeometries`
+:class:`Perimeter`         :class:`LineLocatePoint`                          :class:`SnapToGrid`      :class:`FromWKB`    :class:`AsWKB`      :class:`NumPoints`
+                           :class:`PointOnSurface`                           :class:`Transform`       :class:`FromWKT`    :class:`AsWKT`
+                                                                             :class:`Translate`                           :class:`GeoHash`
+=========================  ========================  ======================  =======================  ==================  ==================  ======================
 
 ``Area``
 ========
@@ -174,15 +174,13 @@ __ https://www.w3.org/Graphics/SVG/
 Oracle, `PostGIS <https://postgis.net/docs/ST_AsBinary.html>`__, SpatiaLite
 
 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::
 
     >>> 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@'
 
-__ https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry#Well-known_binary
-
 ``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
 
 Accepts a single geographic field or expression and returns a `Well-known text
-(WKT)`__ representation of the geometry.
+(WKT)`_ representation of the geometry.
 
 Example::
 
     >>> City.objects.annotate(wkt=AsWKT('point')).get(name='Chelyabinsk').wkt
     'POINT (55.137555 61.451728)'
 
-__ https://en.wikipedia.org/wiki/Well-known_text_representation_of_geometry
-
 ``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
 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``
 ===========
 
@@ -596,3 +618,6 @@ parameters.
 
 Accepts two geographic fields or expressions and returns the union of both
 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

+ 5 - 0
docs/releases/4.2.txt

@@ -167,6 +167,11 @@ Minor features
   :class:`IsEmpty() <django.contrib.gis.db.models.functions.IsEmpty>`
   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`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

+ 18 - 0
tests/gis_tests/geoapp/test_functions.py

@@ -326,6 +326,24 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
         ).get(name="Foo")
         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")
     def test_geohash(self):
         # Reference query: