0
0
mirror of https://github.com/django/django.git synced 2024-11-21 19:09:18 +01:00

added support for geom_type lookup

This commit is contained in:
leondaz 2024-10-12 07:39:30 +03:00
parent 35ab2e0182
commit 94d86713a4
4 changed files with 127 additions and 4 deletions

View File

@ -8,6 +8,7 @@ from django.db import NotSupportedError
from django.db.models import ( from django.db.models import (
BinaryField, BinaryField,
BooleanField, BooleanField,
CharField,
FloatField, FloatField,
Func, Func,
IntegerField, IntegerField,
@ -421,6 +422,37 @@ class Intersection(OracleToleranceMixin, GeomOutputGeoFunc):
geom_param_pos = (0, 1) geom_param_pos = (0, 1)
@BaseSpatialField.register_lookup
class GeometryType(GeoFuncMixin, Transform):
function = "GeometryType"
output_field = CharField()
lookup_name = "geom_type"
def as_mysql(self, compiler, connection, **extra_context):
lhs, params = compiler.compile(self.lhs)
sql = f"ST_GeometryType({lhs})"
return sql, params
def as_oracle(self, compiler, connection, **extra_context):
lhs, params = compiler.compile(self.lhs)
sql = f"""
(SELECT DECODE(
SDO_GEOMETRY.GET_GTYPE({lhs}),
1, 'POINT',
2, 'LINESTRING',
3, 'POLYGON',
4, 'COLLECTION',
5, 'MULTIPOINT',
6, 'MULTILINESTRING',
7, 'MULTIPOLYGON',
8, 'SOLID',
'UNKNOWN')
)
"""
return sql, params
@BaseSpatialField.register_lookup @BaseSpatialField.register_lookup
class IsEmpty(GeoFuncMixin, Transform): class IsEmpty(GeoFuncMixin, Transform):
lookup_name = "isempty" lookup_name = "isempty"

View File

@ -692,6 +692,34 @@ PostGIS equivalent:
.. _distance-lookups: .. _distance-lookups:
.. fieldlookup:: geom_type
``geom_type``
-----------------
*Availability*: `PostGIS <https://postgis.net/docs/GeometryType.html>`__,
Oracle, MariaDB, MySQL, SpatiaLite
Returns the geometry type of the geometry field.
Example::
Shape.objects.filter(poly__geom_type=GeometryType("circle"))
========== ==========================
Backend SQL Equivalent
========== ==========================
PostGIS ``GeometryType(geom)``
MariaDB ``ST_GeometryType(geom)``
MySQL ``ST_GeometryType(geom)``
Oracle ``SDO_GEOMETRY.GET_GTYPE(geom)``
SpatiaLite ``GeometryType(geom)``
========== ==========================
Note that the ``GeometryType`` functions returns the string type but
``SDO_GEOMETRY.GET_GTYPE`` function returns the type encoded as a number.
Thus, those numbers are mapped to the string counterparts as per `Oracle's documentation <https://docs.oracle.com/database/121/SPATL/sdo_geometry-object-type.htm#GUID-4D84CE67-67E4-4A84-8255-C586E765A94B__G1013735>`_
Distance Lookups Distance Lookups
================ ================

View File

@ -99,6 +99,7 @@ Minor features
:attr:`.OGRGeometry.has_curve` property, and the :attr:`.OGRGeometry.has_curve` property, and the
:meth:`.OGRGeometry.get_linear_geometry` and :meth:`.OGRGeometry.get_linear_geometry` and
:meth:`.OGRGeometry.get_curve_geometry` methods. :meth:`.OGRGeometry.get_curve_geometry` methods.
* Introduced :lookup:`geom_type` lookup to allow filtering by geometry type (:ticket:`28696`)
:mod:`django.contrib.messages` :mod:`django.contrib.messages`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -4,14 +4,31 @@ import re
from decimal import Decimal from decimal import Decimal
from django.contrib.gis.db.models import GeometryField, PolygonField, functions from django.contrib.gis.db.models import GeometryField, PolygonField, functions
from django.contrib.gis.geos import GEOSGeometry, LineString, Point, Polygon, fromstr from django.contrib.gis.geos import (
GEOSGeometry,
LineString,
MultiLineString,
MultiPoint,
MultiPolygon,
Point,
Polygon,
fromstr,
)
from django.contrib.gis.measure import Area from django.contrib.gis.measure import Area
from django.db import NotSupportedError, connection from django.db import NotSupportedError, connection
from django.db.models import IntegerField, Sum, Value from django.db.models import F, IntegerField, Sum, Value
from django.test import TestCase, skipUnlessDBFeature from django.test import TestCase, skipUnlessAnyDBFeature, skipUnlessDBFeature
from ..utils import FuncTestMixin from ..utils import FuncTestMixin
from .models import City, Country, CountryWebMercator, ManyPointModel, State, Track from .models import (
City,
Country,
CountryWebMercator,
Feature,
ManyPointModel,
State,
Track,
)
class GISFunctionsTests(FuncTestMixin, TestCase): class GISFunctionsTests(FuncTestMixin, TestCase):
@ -845,3 +862,48 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
City.objects.annotate(union=functions.GeoFunc(1, "point")).get( City.objects.annotate(union=functions.GeoFunc(1, "point")).get(
name="Dallas" name="Dallas"
) )
class GeometryTypeFunctionTests(TestCase):
@classmethod
def setUpTestData(cls):
cls.features = [
Feature.objects.create(name="Point", geom=Point(0, 0)),
Feature.objects.create(name="LineString", geom=LineString((0, 0), (1, 1))),
Feature.objects.create(
name="Polygon", geom=Polygon(((0, 0), (1, 0), (1, 1), (0, 0)))
),
Feature.objects.create(
name="MultiPoint", geom=MultiPoint(Point(0, 0), Point(1, 1))
),
Feature.objects.create(
name="MultiLineString",
geom=MultiLineString(
LineString((0, 0), (1, 1)), LineString((1, 1), (2, 2))
),
),
Feature.objects.create(
name="MultiPolygon",
geom=MultiPolygon(
Polygon(((0, 0), (1, 0), (1, 1), (0, 0))),
Polygon(((1, 1), (2, 1), (2, 2), (1, 1))),
),
),
]
@skipUnlessAnyDBFeature("has_GeometryType_function", "has_SDO_GTYPE_function")
def test_geometry_type_transform(self):
qs = Feature.objects.annotate(geom_type=F("geom__geom_type"))
expected_results = {
"Point": "POINT",
"LineString": "LINESTRING",
"Polygon": "POLYGON",
"MultiPoint": "MULTIPOINT",
"MultiLineString": "MULTILINESTRING",
"MultiPolygon": "MULTIPOLYGON",
}
for feature in qs:
expected_type = expected_results[feature.name]
self.assertEqual(feature.geom_type.upper(), expected_type)