mirror of https://github.com/django/django.git
Fixed #33783 -- Added IsEmpty GIS database function and __isempty lookup on PostGIS.
This commit is contained in:
parent
6774e9359c
commit
2a14b8df39
|
@ -48,6 +48,7 @@ class BaseSpatialOperations:
|
||||||
"GeoHash",
|
"GeoHash",
|
||||||
"GeometryDistance",
|
"GeometryDistance",
|
||||||
"Intersection",
|
"Intersection",
|
||||||
|
"IsEmpty",
|
||||||
"IsValid",
|
"IsValid",
|
||||||
"Length",
|
"Length",
|
||||||
"LineLocatePoint",
|
"LineLocatePoint",
|
||||||
|
|
|
@ -72,6 +72,7 @@ class MySQLOperations(BaseSpatialOperations, DatabaseOperations):
|
||||||
"BoundingCircle",
|
"BoundingCircle",
|
||||||
"ForcePolygonCW",
|
"ForcePolygonCW",
|
||||||
"GeometryDistance",
|
"GeometryDistance",
|
||||||
|
"IsEmpty",
|
||||||
"LineLocatePoint",
|
"LineLocatePoint",
|
||||||
"MakeValid",
|
"MakeValid",
|
||||||
"MemSize",
|
"MemSize",
|
||||||
|
|
|
@ -122,6 +122,7 @@ class OracleOperations(BaseSpatialOperations, DatabaseOperations):
|
||||||
"ForcePolygonCW",
|
"ForcePolygonCW",
|
||||||
"GeoHash",
|
"GeoHash",
|
||||||
"GeometryDistance",
|
"GeometryDistance",
|
||||||
|
"IsEmpty",
|
||||||
"LineLocatePoint",
|
"LineLocatePoint",
|
||||||
"MakeValid",
|
"MakeValid",
|
||||||
"MemSize",
|
"MemSize",
|
||||||
|
|
|
@ -78,7 +78,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def unsupported_functions(self):
|
def unsupported_functions(self):
|
||||||
unsupported = {"BoundingCircle", "GeometryDistance", "MemSize"}
|
unsupported = {"BoundingCircle", "GeometryDistance", "IsEmpty", "MemSize"}
|
||||||
if not self.geom_lib_version():
|
if not self.geom_lib_version():
|
||||||
unsupported |= {"Azimuth", "GeoHash", "MakeValid"}
|
unsupported |= {"Azimuth", "GeoHash", "MakeValid"}
|
||||||
return unsupported
|
return unsupported
|
||||||
|
|
|
@ -381,6 +381,12 @@ class Intersection(OracleToleranceMixin, GeomOutputGeoFunc):
|
||||||
geom_param_pos = (0, 1)
|
geom_param_pos = (0, 1)
|
||||||
|
|
||||||
|
|
||||||
|
@BaseSpatialField.register_lookup
|
||||||
|
class IsEmpty(GeoFuncMixin, Transform):
|
||||||
|
lookup_name = "isempty"
|
||||||
|
output_field = BooleanField()
|
||||||
|
|
||||||
|
|
||||||
@BaseSpatialField.register_lookup
|
@BaseSpatialField.register_lookup
|
||||||
class IsValid(OracleToleranceMixin, GeoFuncMixin, Transform):
|
class IsValid(OracleToleranceMixin, GeoFuncMixin, Transform):
|
||||||
lookup_name = "isvalid"
|
lookup_name = "isvalid"
|
||||||
|
|
|
@ -316,6 +316,7 @@ Lookup Type PostGIS Oracle MariaDB MySQL [#]_ Sp
|
||||||
:lookup:`equals` X X X X X C
|
:lookup:`equals` X X X X X C
|
||||||
:lookup:`exact <same_as>` X X X X X B
|
:lookup:`exact <same_as>` X X X X X B
|
||||||
:lookup:`intersects` X X X X X B
|
:lookup:`intersects` X X X X X B
|
||||||
|
:lookup:`isempty` X
|
||||||
:lookup:`isvalid` X X X X
|
:lookup:`isvalid` X X X X
|
||||||
:lookup:`overlaps` X X X X X B
|
:lookup:`overlaps` X X X X X B
|
||||||
:lookup:`relate` X X X X C
|
:lookup:`relate` X X X X C
|
||||||
|
@ -361,6 +362,7 @@ Function PostGIS Oracle MariaDB MySQL
|
||||||
:class:`ForcePolygonCW` X X
|
:class:`ForcePolygonCW` 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:`IsValid` X X X X
|
:class:`IsValid` X X X X
|
||||||
:class:`Length` X X X X X
|
:class:`Length` X X X X X
|
||||||
:class:`LineLocatePoint` X X
|
:class:`LineLocatePoint` X X
|
||||||
|
|
|
@ -23,11 +23,11 @@ Function's summary:
|
||||||
========================= ======================== ====================== ======================= ================== =====================
|
========================= ======================== ====================== ======================= ================== =====================
|
||||||
Measurement Relationships Operations Editors Output format Miscellaneous
|
Measurement Relationships Operations Editors Output format Miscellaneous
|
||||||
========================= ======================== ====================== ======================= ================== =====================
|
========================= ======================== ====================== ======================= ================== =====================
|
||||||
:class:`Area` :class:`Azimuth` :class:`Difference` :class:`ForcePolygonCW` :class:`AsGeoJSON` :class:`IsValid`
|
:class:`Area` :class:`Azimuth` :class:`Difference` :class:`ForcePolygonCW` :class:`AsGeoJSON` :class:`IsEmpty`
|
||||||
:class:`Distance` :class:`BoundingCircle` :class:`Intersection` :class:`MakeValid` :class:`AsGML` :class:`MemSize`
|
:class:`Distance` :class:`BoundingCircle` :class:`Intersection` :class:`MakeValid` :class:`AsGML` :class:`IsValid`
|
||||||
:class:`GeometryDistance` :class:`Centroid` :class:`SymDifference` :class:`Reverse` :class:`AsKML` :class:`NumGeometries`
|
:class:`GeometryDistance` :class:`Centroid` :class:`SymDifference` :class:`Reverse` :class:`AsKML` :class:`MemSize`
|
||||||
:class:`Length` :class:`Envelope` :class:`Union` :class:`Scale` :class:`AsSVG` :class:`NumPoints`
|
:class:`Length` :class:`Envelope` :class:`Union` :class:`Scale` :class:`AsSVG` :class:`NumGeometries`
|
||||||
:class:`Perimeter` :class:`LineLocatePoint` :class:`SnapToGrid` :class:`AsWKB`
|
:class:`Perimeter` :class:`LineLocatePoint` :class:`SnapToGrid` :class:`AsWKB` :class:`NumPoints`
|
||||||
.. :class:`PointOnSurface` :class:`Transform` :class:`AsWKT`
|
.. :class:`PointOnSurface` :class:`Transform` :class:`AsWKT`
|
||||||
.. :class:`Translate` :class:`GeoHash`
|
.. :class:`Translate` :class:`GeoHash`
|
||||||
========================= ======================== ====================== ======================= ================== =====================
|
========================= ======================== ====================== ======================= ================== =====================
|
||||||
|
@ -368,6 +368,18 @@ it provides index-assisted nearest-neighbor result sets.
|
||||||
Accepts two geographic fields or expressions and returns the geometric
|
Accepts two geographic fields or expressions and returns the geometric
|
||||||
intersection between them.
|
intersection between them.
|
||||||
|
|
||||||
|
``IsEmpty``
|
||||||
|
===========
|
||||||
|
|
||||||
|
.. versionadded:: 4.2
|
||||||
|
|
||||||
|
.. class:: IsEmpty(expr)
|
||||||
|
|
||||||
|
*Availability*: `PostGIS <https://postgis.net/docs/ST_IsEmpty.html>`__
|
||||||
|
|
||||||
|
Accepts a geographic field or expression and tests if the value is an empty
|
||||||
|
geometry. Returns ``True`` if its value is empty and ``False`` otherwise.
|
||||||
|
|
||||||
``IsValid``
|
``IsValid``
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
|
|
@ -346,6 +346,21 @@ MySQL ``ST_Intersects(poly, geom)``
|
||||||
SpatiaLite ``Intersects(poly, geom)``
|
SpatiaLite ``Intersects(poly, geom)``
|
||||||
========== =================================================
|
========== =================================================
|
||||||
|
|
||||||
|
.. fieldlookup:: isempty
|
||||||
|
|
||||||
|
``isempty``
|
||||||
|
-----------
|
||||||
|
|
||||||
|
.. versionadded:: 4.2
|
||||||
|
|
||||||
|
*Availability*: `PostGIS <https://postgis.net/docs/ST_IsEmpty.html>`__
|
||||||
|
|
||||||
|
Tests if the geometry is empty.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
Zipcode.objects.filter(poly__isempty=True)
|
||||||
|
|
||||||
.. fieldlookup:: isvalid
|
.. fieldlookup:: isvalid
|
||||||
|
|
||||||
``isvalid``
|
``isvalid``
|
||||||
|
|
|
@ -155,6 +155,10 @@ Minor features
|
||||||
* :class:`~django.contrib.gis.forms.widgets.OpenLayersWidget` is now based on
|
* :class:`~django.contrib.gis.forms.widgets.OpenLayersWidget` is now based on
|
||||||
OpenLayers 7.2.2 (previously 4.6.5).
|
OpenLayers 7.2.2 (previously 4.6.5).
|
||||||
|
|
||||||
|
* The new :lookup:`isempty` lookup and
|
||||||
|
:class:`IsEmpty() <django.contrib.gis.db.models.functions.IsEmpty>`
|
||||||
|
expression allow filtering empty geometries on PostGIS.
|
||||||
|
|
||||||
:mod:`django.contrib.messages`
|
:mod:`django.contrib.messages`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -371,6 +371,18 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertIs(c.inter.empty, True)
|
self.assertIs(c.inter.empty, True)
|
||||||
|
|
||||||
|
@skipUnlessDBFeature("supports_empty_geometries", "has_IsEmpty_function")
|
||||||
|
def test_isempty(self):
|
||||||
|
empty = City.objects.create(name="Nowhere", point=Point(srid=4326))
|
||||||
|
City.objects.create(name="Somewhere", point=Point(6.825, 47.1, srid=4326))
|
||||||
|
self.assertSequenceEqual(
|
||||||
|
City.objects.annotate(isempty=functions.IsEmpty("point")).filter(
|
||||||
|
isempty=True
|
||||||
|
),
|
||||||
|
[empty],
|
||||||
|
)
|
||||||
|
self.assertSequenceEqual(City.objects.filter(point__isempty=True), [empty])
|
||||||
|
|
||||||
@skipUnlessDBFeature("has_IsValid_function")
|
@skipUnlessDBFeature("has_IsValid_function")
|
||||||
def test_isvalid(self):
|
def test_isvalid(self):
|
||||||
valid_geom = fromstr("POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))")
|
valid_geom = fromstr("POLYGON((0 0, 0 1, 1 1, 1 0, 0 0))")
|
||||||
|
|
Loading…
Reference in New Issue