mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Refs #33783 -- Added IsEmpty GIS database function and __isempty lookup on SpatiaLite.
This commit is contained in:
parent
43287cbb87
commit
1e67d1a061
@ -82,7 +82,7 @@ class SpatiaLiteOperations(BaseSpatialOperations, DatabaseOperations):
|
|||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def unsupported_functions(self):
|
def unsupported_functions(self):
|
||||||
unsupported = {"GeometryDistance", "IsEmpty", "MemSize"}
|
unsupported = {"GeometryDistance", "MemSize"}
|
||||||
if not self.geom_lib_version():
|
if not self.geom_lib_version():
|
||||||
unsupported |= {"Azimuth", "GeoHash", "MakeValid"}
|
unsupported |= {"Azimuth", "GeoHash", "MakeValid"}
|
||||||
if self.spatial_version < (5, 1):
|
if self.spatial_version < (5, 1):
|
||||||
|
@ -359,7 +359,7 @@ Lookup Type PostGIS Oracle MariaDB MySQL [#]_ S
|
|||||||
: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:`isempty` X X
|
||||||
:lookup:`isvalid` X X X (≥ 11.7) X X
|
:lookup:`isvalid` X X X (≥ 11.7) 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
|
||||||
@ -408,7 +408,7 @@ Function PostGIS Oracle MariaDB MySQL
|
|||||||
:class:`FromWKT` X X X X X
|
:class:`FromWKT` X X X X X
|
||||||
:class:`GeoHash` X X (≥ 11.7) X X (LWGEOM/RTTOPO)
|
:class:`GeoHash` X X (≥ 11.7) X X (LWGEOM/RTTOPO)
|
||||||
:class:`Intersection` X X X X X
|
:class:`Intersection` X X X X X
|
||||||
:class:`IsEmpty` X
|
:class:`IsEmpty` X X
|
||||||
:class:`IsValid` X X X (≥ 11.7) X X
|
:class:`IsValid` X X X (≥ 11.7) X X
|
||||||
:class:`Length` X X X X X
|
:class:`Length` X X X X X
|
||||||
:class:`LineLocatePoint` X X
|
:class:`LineLocatePoint` X X
|
||||||
|
@ -438,11 +438,16 @@ intersection between them.
|
|||||||
|
|
||||||
.. class:: IsEmpty(expr)
|
.. class:: IsEmpty(expr)
|
||||||
|
|
||||||
*Availability*: `PostGIS <https://postgis.net/docs/ST_IsEmpty.html>`__
|
*Availability*: `PostGIS <https://postgis.net/docs/ST_IsEmpty.html>`__,
|
||||||
|
SpatiaLite
|
||||||
|
|
||||||
Accepts a geographic field or expression and tests if the value is an empty
|
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.
|
geometry. Returns ``True`` if its value is empty and ``False`` otherwise.
|
||||||
|
|
||||||
|
.. versionchanged:: 5.2
|
||||||
|
|
||||||
|
Support for SpatiaLite was added.
|
||||||
|
|
||||||
``IsValid``
|
``IsValid``
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
@ -362,7 +362,8 @@ SpatiaLite ``Intersects(poly, geom)``
|
|||||||
``isempty``
|
``isempty``
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
*Availability*: `PostGIS <https://postgis.net/docs/ST_IsEmpty.html>`__
|
*Availability*: `PostGIS <https://postgis.net/docs/ST_IsEmpty.html>`__,
|
||||||
|
SpatiaLite
|
||||||
|
|
||||||
Tests if the geometry is empty.
|
Tests if the geometry is empty.
|
||||||
|
|
||||||
@ -372,6 +373,10 @@ Example::
|
|||||||
|
|
||||||
.. fieldlookup:: isvalid
|
.. fieldlookup:: isvalid
|
||||||
|
|
||||||
|
.. versionchanged:: 5.2
|
||||||
|
|
||||||
|
Support for SpatiaLite was added.
|
||||||
|
|
||||||
``isvalid``
|
``isvalid``
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@ -108,6 +108,10 @@ Minor features
|
|||||||
:class:`~django.contrib.gis.db.models.functions.IsValid` database functions
|
:class:`~django.contrib.gis.db.models.functions.IsValid` database functions
|
||||||
are now supported on MariaDB 11.7+.
|
are now supported on MariaDB 11.7+.
|
||||||
|
|
||||||
|
* The :lookup:`isempty` lookup and
|
||||||
|
:class:`~django.contrib.gis.db.models.functions.IsEmpty` expression are now
|
||||||
|
supported on SpatiaLite.
|
||||||
|
|
||||||
:mod:`django.contrib.messages`
|
:mod:`django.contrib.messages`
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -28,6 +28,13 @@ class City(NamedModel):
|
|||||||
app_label = "geoapp"
|
app_label = "geoapp"
|
||||||
|
|
||||||
|
|
||||||
|
class Town(NamedModel):
|
||||||
|
point = models.PointField(null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = "geoapp"
|
||||||
|
|
||||||
|
|
||||||
# This is an inherited model from City
|
# This is an inherited model from City
|
||||||
class PennsylvaniaCity(City):
|
class PennsylvaniaCity(City):
|
||||||
county = models.CharField(max_length=30)
|
county = models.CharField(max_length=30)
|
||||||
|
@ -11,7 +11,15 @@ from django.db.models import IntegerField, Sum, Value
|
|||||||
from django.test import TestCase, skipUnlessDBFeature
|
from django.test import TestCase, skipUnlessDBFeature
|
||||||
|
|
||||||
from ..utils import FuncTestMixin
|
from ..utils import FuncTestMixin
|
||||||
from .models import City, Country, CountryWebMercator, ManyPointModel, State, Track
|
from .models import (
|
||||||
|
City,
|
||||||
|
Country,
|
||||||
|
CountryWebMercator,
|
||||||
|
ManyPointModel,
|
||||||
|
State,
|
||||||
|
Town,
|
||||||
|
Track,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class GISFunctionsTests(FuncTestMixin, TestCase):
|
class GISFunctionsTests(FuncTestMixin, TestCase):
|
||||||
@ -413,7 +421,7 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
|||||||
self.assertIs(c.inter.empty, True)
|
self.assertIs(c.inter.empty, True)
|
||||||
|
|
||||||
@skipUnlessDBFeature("supports_empty_geometries", "has_IsEmpty_function")
|
@skipUnlessDBFeature("supports_empty_geometries", "has_IsEmpty_function")
|
||||||
def test_isempty(self):
|
def test_isempty_empty_geometry(self):
|
||||||
empty = City.objects.create(name="Nowhere", point=Point(srid=4326))
|
empty = City.objects.create(name="Nowhere", point=Point(srid=4326))
|
||||||
City.objects.create(name="Somewhere", point=Point(6.825, 47.1, srid=4326))
|
City.objects.create(name="Somewhere", point=Point(6.825, 47.1, srid=4326))
|
||||||
self.assertSequenceEqual(
|
self.assertSequenceEqual(
|
||||||
@ -424,6 +432,29 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
|
|||||||
)
|
)
|
||||||
self.assertSequenceEqual(City.objects.filter(point__isempty=True), [empty])
|
self.assertSequenceEqual(City.objects.filter(point__isempty=True), [empty])
|
||||||
|
|
||||||
|
@skipUnlessDBFeature("has_IsEmpty_function")
|
||||||
|
def test_isempty_null_geometry(self):
|
||||||
|
null_geometry = Town.objects.create(name="Nowhere", point=None)
|
||||||
|
Town.objects.create(name="Somewhere", point=Point(6.825, 47.1, srid=4326))
|
||||||
|
if connection.ops.spatialite:
|
||||||
|
self.assertSequenceEqual(
|
||||||
|
Town.objects.annotate(isempty=functions.IsEmpty("point")).filter(
|
||||||
|
isempty=True
|
||||||
|
),
|
||||||
|
[null_geometry],
|
||||||
|
)
|
||||||
|
self.assertSequenceEqual(
|
||||||
|
Town.objects.filter(point__isempty=True), [null_geometry]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.assertSequenceEqual(
|
||||||
|
Town.objects.annotate(isempty=functions.IsEmpty("point")).filter(
|
||||||
|
isempty=True
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
self.assertSequenceEqual(Town.objects.filter(point__isempty=True), [])
|
||||||
|
|
||||||
@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
Block a user