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 (
BinaryField,
BooleanField,
CharField,
FloatField,
Func,
IntegerField,
@ -421,6 +422,37 @@ class Intersection(OracleToleranceMixin, GeomOutputGeoFunc):
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
class IsEmpty(GeoFuncMixin, Transform):
lookup_name = "isempty"

View File

@ -692,6 +692,34 @@ PostGIS equivalent:
.. _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
================

View File

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

View File

@ -4,14 +4,31 @@ import re
from decimal import Decimal
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.db import NotSupportedError, connection
from django.db.models import IntegerField, Sum, Value
from django.test import TestCase, skipUnlessDBFeature
from django.db.models import F, IntegerField, Sum, Value
from django.test import TestCase, skipUnlessAnyDBFeature, skipUnlessDBFeature
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):
@ -845,3 +862,48 @@ class GISFunctionsTests(FuncTestMixin, TestCase):
City.objects.annotate(union=functions.GeoFunc(1, "point")).get(
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)