From e3ed66b7980d10a371dfbe050b93d26e32a6f503 Mon Sep 17 00:00:00 2001 From: Evan Moon Date: Sun, 16 Feb 2025 20:06:49 +0900 Subject: [PATCH 01/10] Add Geometry filter --- strawberry_django/__init__.py | 2 ++ strawberry_django/fields/filter_types.py | 30 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/strawberry_django/__init__.py b/strawberry_django/__init__.py index 74e0a557..365261b1 100644 --- a/strawberry_django/__init__.py +++ b/strawberry_django/__init__.py @@ -9,6 +9,7 @@ FilterLookup, RangeLookup, TimeFilterLookup, + GeometryFilterLookup, ) from .fields.types import ( DjangoFileType, @@ -47,6 +48,7 @@ "Ordering", "RangeLookup", "TimeFilterLookup", + "GeometryFilterLookup", "auth", "connection", "django_resolver", diff --git a/strawberry_django/fields/filter_types.py b/strawberry_django/fields/filter_types.py index 1c05ccbb..aa6d4920 100644 --- a/strawberry_django/fields/filter_types.py +++ b/strawberry_django/fields/filter_types.py @@ -5,15 +5,20 @@ Generic, Optional, TypeVar, + Annotated, + TYPE_CHECKING, ) import strawberry +from django.core.exceptions import ImproperlyConfigured from django.db.models import Q from strawberry import UNSET from strawberry_django.filters import resolve_value from .filter_order import filter_field +if TYPE_CHECKING: + from .types import Geometry T = TypeVar("T") @@ -123,3 +128,28 @@ class DatetimeFilterLookup(DateFilterLookup[T], TimeFilterLookup[T]): str: FilterLookup, uuid.UUID: FilterLookup, } + + +try: + from django.contrib.gis import geos + from django.contrib.gis.db import models as geos_fields + +except ImproperlyConfigured: + # If gdal is not available, skip. + pass +else: + @strawberry.input + class GeometryFilterLookup(Generic[T]): + intersects: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + + type_filter_map.update( + { + geos_fields.PointField: GeometryFilterLookup, + geos_fields.LineStringField: GeometryFilterLookup, + geos_fields.PolygonField: GeometryFilterLookup, + geos_fields.MultiPointField: GeometryFilterLookup, + geos_fields.MultiLineStringField: GeometryFilterLookup, + geos_fields.MultiPolygonField: GeometryFilterLookup, + Geometry: GeometryFilterLookup, + }, + ) From fb3a065a26dfabe389d97e5149d02ce953335e6d Mon Sep 17 00:00:00 2001 From: Evan Moon Date: Mon, 17 Feb 2025 20:07:42 +0900 Subject: [PATCH 02/10] Add GeometryLooupFilter --- poetry.lock | 2 ++ strawberry_django/__init__.py | 12 ++++++++++-- strawberry_django/fields/filter_types.py | 16 +--------------- strawberry_django/fields/types.py | 15 +++------------ 4 files changed, 16 insertions(+), 29 deletions(-) diff --git a/poetry.lock b/poetry.lock index b2066bee..f574d073 100644 --- a/poetry.lock +++ b/poetry.lock @@ -461,6 +461,7 @@ files = [ {file = "psycopg2-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:0435034157049f6846e95103bd8f5a668788dd913a7c30162ca9503fdf542cb4"}, {file = "psycopg2-2.9.10-cp312-cp312-win32.whl", hash = "sha256:65a63d7ab0e067e2cdb3cf266de39663203d38d6a8ed97f5ca0cb315c73fe067"}, {file = "psycopg2-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:4a579d6243da40a7b3182e0430493dbd55950c493d8c68f4eec0b302f6bbf20e"}, + {file = "psycopg2-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:91fd603a2155da8d0cfcdbf8ab24a2d54bca72795b90d2a3ed2b6da8d979dee2"}, {file = "psycopg2-2.9.10-cp39-cp39-win32.whl", hash = "sha256:9d5b3b94b79a844a986d029eee38998232451119ad653aea42bb9220a8c5066b"}, {file = "psycopg2-2.9.10-cp39-cp39-win_amd64.whl", hash = "sha256:88138c8dedcbfa96408023ea2b0c369eda40fe5d75002c0964c78f46f11fa442"}, {file = "psycopg2-2.9.10.tar.gz", hash = "sha256:12ec0b40b0273f95296233e8750441339298e6a572f7039da5b260e3c8b60e11"}, @@ -521,6 +522,7 @@ files = [ {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"}, diff --git a/strawberry_django/__init__.py b/strawberry_django/__init__.py index 365261b1..f208e6d8 100644 --- a/strawberry_django/__init__.py +++ b/strawberry_django/__init__.py @@ -9,7 +9,6 @@ FilterLookup, RangeLookup, TimeFilterLookup, - GeometryFilterLookup, ) from .fields.types import ( DjangoFileType, @@ -29,6 +28,7 @@ from .resolvers import django_resolver from .type import input, interface, partial, type # noqa: A004 + __all__ = [ "BaseFilterLookup", "ComparisonFilterLookup", @@ -48,7 +48,6 @@ "Ordering", "RangeLookup", "TimeFilterLookup", - "GeometryFilterLookup", "auth", "connection", "django_resolver", @@ -73,3 +72,12 @@ "relay", "type", ] + +from django.core.exceptions import ImproperlyConfigured + +try: + from .fields.filter_types import GeometryFilterLookup + __all__.extend(["GeometryFilterLookup"]) +except ImproperlyConfigured: + # If gdal is not available, skip. + pass diff --git a/strawberry_django/fields/filter_types.py b/strawberry_django/fields/filter_types.py index aa6d4920..fb7f7dc4 100644 --- a/strawberry_django/fields/filter_types.py +++ b/strawberry_django/fields/filter_types.py @@ -131,9 +131,7 @@ class DatetimeFilterLookup(DateFilterLookup[T], TimeFilterLookup[T]): try: - from django.contrib.gis import geos - from django.contrib.gis.db import models as geos_fields - + import django.contrib.gis except ImproperlyConfigured: # If gdal is not available, skip. pass @@ -141,15 +139,3 @@ class DatetimeFilterLookup(DateFilterLookup[T], TimeFilterLookup[T]): @strawberry.input class GeometryFilterLookup(Generic[T]): intersects: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET - - type_filter_map.update( - { - geos_fields.PointField: GeometryFilterLookup, - geos_fields.LineStringField: GeometryFilterLookup, - geos_fields.PolygonField: GeometryFilterLookup, - geos_fields.MultiPointField: GeometryFilterLookup, - geos_fields.MultiLineStringField: GeometryFilterLookup, - geos_fields.MultiPolygonField: GeometryFilterLookup, - Geometry: GeometryFilterLookup, - }, - ) diff --git a/strawberry_django/fields/types.py b/strawberry_django/fields/types.py index fe54f045..09851a9b 100644 --- a/strawberry_django/fields/types.py +++ b/strawberry_django/fields/types.py @@ -24,6 +24,7 @@ from strawberry.file_uploads.scalars import Upload from strawberry.scalars import JSON from strawberry.types.enum import EnumValueDefinition +from strawberry.types.scalar import ScalarWrapper from strawberry.utils.str_converters import capitalize_first, to_camel_case from strawberry_django import filters @@ -355,18 +356,6 @@ def __hash__(self): ), ) - field_type_map.update( - { - geos_fields.PointField: Point, - geos_fields.LineStringField: LineString, - geos_fields.PolygonField: Polygon, - geos_fields.MultiPointField: MultiPoint, - geos_fields.MultiLineStringField: MultiLineString, - geos_fields.MultiPolygonField: MultiPolygon, - geos_fields.GeometryField: Geometry, - }, - ) - input_field_type_map: dict[ Union[ @@ -557,6 +546,8 @@ def resolve_model_field_type( ): if using_old_filters: field_type = filters.FilterLookup[field_type] + elif type(field_type) is ScalarWrapper and field_type._scalar_definition.name in ("Point", "LineString", "LinearRing", "Polygon", "MultiPoint", "MultilineString", "MultiPolygon", "Geometry"): + field_type = filter_types.GeometryFilterLookup[field_type] else: field_type = filter_types.type_filter_map.get( # type: ignore field_type, filter_types.FilterLookup From 3fc6b2c917161c3ebb89f3d88b897c0cd244fd59 Mon Sep 17 00:00:00 2001 From: Evan Moon Date: Mon, 17 Feb 2025 20:37:39 +0900 Subject: [PATCH 03/10] Refactor intersects parameter --- strawberry_django/fields/filter_types.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/strawberry_django/fields/filter_types.py b/strawberry_django/fields/filter_types.py index fb7f7dc4..16b474e6 100644 --- a/strawberry_django/fields/filter_types.py +++ b/strawberry_django/fields/filter_types.py @@ -4,6 +4,7 @@ from typing import ( Generic, Optional, + Union, TypeVar, Annotated, TYPE_CHECKING, @@ -138,4 +139,4 @@ class DatetimeFilterLookup(DateFilterLookup[T], TimeFilterLookup[T]): else: @strawberry.input class GeometryFilterLookup(Generic[T]): - intersects: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + intersects: Optional[Union[Annotated["Point", strawberry.lazy(".types")], Annotated["MultiPoint", strawberry.lazy(".types")]]] = UNSET From 2e3e35b637961ac7d5647c0ac1bd0d72c4d3ecfa Mon Sep 17 00:00:00 2001 From: Evan Moon Date: Mon, 17 Feb 2025 20:56:17 +0900 Subject: [PATCH 04/10] Undo remove field_type_map --- strawberry_django/fields/types.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/strawberry_django/fields/types.py b/strawberry_django/fields/types.py index 09851a9b..8d10a842 100644 --- a/strawberry_django/fields/types.py +++ b/strawberry_django/fields/types.py @@ -356,6 +356,18 @@ def __hash__(self): ), ) + field_type_map.update( + { + geos_fields.PointField: Point, + geos_fields.LineStringField: LineString, + geos_fields.PolygonField: Polygon, + geos_fields.MultiPointField: MultiPoint, + geos_fields.MultiLineStringField: MultiLineString, + geos_fields.MultiPolygonField: MultiPolygon, + geos_fields.GeometryField: Geometry, + }, + ) + input_field_type_map: dict[ Union[ From 744c26013683ec724a1a2d870413afee713dce93 Mon Sep 17 00:00:00 2001 From: Evan Moon Date: Tue, 18 Feb 2025 12:29:46 +0900 Subject: [PATCH 05/10] Add geometry filters --- strawberry_django/__init__.py | 2 +- strawberry_django/fields/filter_types.py | 28 ++++++++++++++++++++++-- strawberry_django/fields/types.py | 2 +- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/strawberry_django/__init__.py b/strawberry_django/__init__.py index f208e6d8..2c73b31a 100644 --- a/strawberry_django/__init__.py +++ b/strawberry_django/__init__.py @@ -77,7 +77,7 @@ try: from .fields.filter_types import GeometryFilterLookup - __all__.extend(["GeometryFilterLookup"]) + __all__.append("GeometryFilterLookup") except ImproperlyConfigured: # If gdal is not available, skip. pass diff --git a/strawberry_django/fields/filter_types.py b/strawberry_django/fields/filter_types.py index 16b474e6..5cf793ee 100644 --- a/strawberry_django/fields/filter_types.py +++ b/strawberry_django/fields/filter_types.py @@ -132,11 +132,35 @@ class DatetimeFilterLookup(DateFilterLookup[T], TimeFilterLookup[T]): try: - import django.contrib.gis + from django.contrib.gis.geos import GEOSGeometry except ImproperlyConfigured: # If gdal is not available, skip. pass else: @strawberry.input class GeometryFilterLookup(Generic[T]): - intersects: Optional[Union[Annotated["Point", strawberry.lazy(".types")], Annotated["MultiPoint", strawberry.lazy(".types")]]] = UNSET + bbcontains: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + bboverlaps: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + contained: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + contains: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + contains_properly: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + coveredby: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + covers: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + crosses: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + disjoint: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + equals: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + exacts: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + intersects: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + isempty: Optional[bool] = filter_field(description=f"Assignment test. {_SKIP_MSG}") + isvalid: Optional[bool] = filter_field(description=f"Assignment test. {_SKIP_MSG}") + overlaps: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + touches: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + within: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + left: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + right: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + overlaps_left: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + overlaps_right: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + overlaps_above: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + overlaps_below: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + strictly_above: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + strictly_below: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET diff --git a/strawberry_django/fields/types.py b/strawberry_django/fields/types.py index 8d10a842..6cc93acd 100644 --- a/strawberry_django/fields/types.py +++ b/strawberry_django/fields/types.py @@ -349,7 +349,7 @@ def __hash__(self): Geometry = strawberry.scalar( NewType("Geometry", geos.GEOSGeometry), serialize=lambda v: v.tuple if isinstance(v, geos.GEOSGeometry) else v, # type: ignore - parse_value=lambda v: geos.GeometryCollection, + parse_value=lambda v: geos.GEOSGeometry(v), description=( "An arbitrary geographical object. One of Point, " "LineString, LinearRing, Polygon, MultiPoint, MultiLineString, MultiPolygon." From a0bfa66ece335d56d21d3943b50c588f2f810354 Mon Sep 17 00:00:00 2001 From: Evan Moon Date: Tue, 18 Feb 2025 21:39:03 +0900 Subject: [PATCH 06/10] Remove unused code --- strawberry_django/__init__.py | 1 - strawberry_django/fields/filter_types.py | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/strawberry_django/__init__.py b/strawberry_django/__init__.py index 2c73b31a..e0fdc9e6 100644 --- a/strawberry_django/__init__.py +++ b/strawberry_django/__init__.py @@ -28,7 +28,6 @@ from .resolvers import django_resolver from .type import input, interface, partial, type # noqa: A004 - __all__ = [ "BaseFilterLookup", "ComparisonFilterLookup", diff --git a/strawberry_django/fields/filter_types.py b/strawberry_django/fields/filter_types.py index 5cf793ee..cc2d09da 100644 --- a/strawberry_django/fields/filter_types.py +++ b/strawberry_django/fields/filter_types.py @@ -4,7 +4,6 @@ from typing import ( Generic, Optional, - Union, TypeVar, Annotated, TYPE_CHECKING, @@ -151,8 +150,8 @@ class GeometryFilterLookup(Generic[T]): equals: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET exacts: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET intersects: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET - isempty: Optional[bool] = filter_field(description=f"Assignment test. {_SKIP_MSG}") - isvalid: Optional[bool] = filter_field(description=f"Assignment test. {_SKIP_MSG}") + isempty: Optional[bool] = filter_field(description=f"Test whether it's empty. {_SKIP_MSG}") + isvalid: Optional[bool] = filter_field(description=f"Test whether it's valid. {_SKIP_MSG}") overlaps: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET touches: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET within: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET From 17ce3f8d116bf88c77dbcded1f75f814d5a8a18c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 18 Feb 2025 12:40:17 +0000 Subject: [PATCH 07/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- strawberry_django/__init__.py | 2 ++ strawberry_django/fields/filter_types.py | 44 +++++++++++++++++------- strawberry_django/fields/types.py | 13 ++++++- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/strawberry_django/__init__.py b/strawberry_django/__init__.py index e0fdc9e6..b2fc34ab 100644 --- a/strawberry_django/__init__.py +++ b/strawberry_django/__init__.py @@ -37,6 +37,7 @@ "DjangoImageType", "DjangoModelType", "FilterLookup", + "GeometryFilterLookup", "ListInput", "ManyToManyInput", "ManyToOneInput", @@ -76,6 +77,7 @@ try: from .fields.filter_types import GeometryFilterLookup + __all__.append("GeometryFilterLookup") except ImproperlyConfigured: # If gdal is not available, skip. diff --git a/strawberry_django/fields/filter_types.py b/strawberry_django/fields/filter_types.py index cc2d09da..bde5bbfa 100644 --- a/strawberry_django/fields/filter_types.py +++ b/strawberry_django/fields/filter_types.py @@ -2,11 +2,11 @@ import decimal import uuid from typing import ( + TYPE_CHECKING, + Annotated, Generic, Optional, TypeVar, - Annotated, - TYPE_CHECKING, ) import strawberry @@ -17,6 +17,7 @@ from strawberry_django.filters import resolve_value from .filter_order import filter_field + if TYPE_CHECKING: from .types import Geometry @@ -131,18 +132,21 @@ class DatetimeFilterLookup(DateFilterLookup[T], TimeFilterLookup[T]): try: - from django.contrib.gis.geos import GEOSGeometry + pass except ImproperlyConfigured: # If gdal is not available, skip. pass else: + @strawberry.input class GeometryFilterLookup(Generic[T]): bbcontains: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET bboverlaps: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET contained: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET contains: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET - contains_properly: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + contains_properly: Optional[ + Annotated["Geometry", strawberry.lazy(".types")] + ] = UNSET coveredby: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET covers: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET crosses: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET @@ -150,16 +154,32 @@ class GeometryFilterLookup(Generic[T]): equals: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET exacts: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET intersects: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET - isempty: Optional[bool] = filter_field(description=f"Test whether it's empty. {_SKIP_MSG}") - isvalid: Optional[bool] = filter_field(description=f"Test whether it's valid. {_SKIP_MSG}") + isempty: Optional[bool] = filter_field( + description=f"Test whether it's empty. {_SKIP_MSG}" + ) + isvalid: Optional[bool] = filter_field( + description=f"Test whether it's valid. {_SKIP_MSG}" + ) overlaps: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET touches: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET within: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET left: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET right: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET - overlaps_left: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET - overlaps_right: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET - overlaps_above: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET - overlaps_below: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET - strictly_above: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET - strictly_below: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = UNSET + overlaps_left: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = ( + UNSET + ) + overlaps_right: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = ( + UNSET + ) + overlaps_above: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = ( + UNSET + ) + overlaps_below: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = ( + UNSET + ) + strictly_above: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = ( + UNSET + ) + strictly_below: Optional[Annotated["Geometry", strawberry.lazy(".types")]] = ( + UNSET + ) diff --git a/strawberry_django/fields/types.py b/strawberry_django/fields/types.py index 6cc93acd..89531371 100644 --- a/strawberry_django/fields/types.py +++ b/strawberry_django/fields/types.py @@ -558,7 +558,18 @@ def resolve_model_field_type( ): if using_old_filters: field_type = filters.FilterLookup[field_type] - elif type(field_type) is ScalarWrapper and field_type._scalar_definition.name in ("Point", "LineString", "LinearRing", "Polygon", "MultiPoint", "MultilineString", "MultiPolygon", "Geometry"): + elif type( + field_type + ) is ScalarWrapper and field_type._scalar_definition.name in ( + "Point", + "LineString", + "LinearRing", + "Polygon", + "MultiPoint", + "MultilineString", + "MultiPolygon", + "Geometry", + ): field_type = filter_types.GeometryFilterLookup[field_type] else: field_type = filter_types.type_filter_map.get( # type: ignore From 95dab27f9bfe4ec1f57044063281dc4833baf767 Mon Sep 17 00:00:00 2001 From: Evan Moon Date: Sun, 6 Apr 2025 15:38:14 +0900 Subject: [PATCH 08/10] Add tests and etc. --- strawberry_django/__init__.py | 12 ++---------- strawberry_django/fields/filter_types.py | 2 ++ strawberry_django/fields/types.py | 15 ++------------- tests/test_queries.py | 20 +++++++++++++++++++- tests/types.py | 1 + 5 files changed, 26 insertions(+), 24 deletions(-) diff --git a/strawberry_django/__init__.py b/strawberry_django/__init__.py index b2fc34ab..de298f56 100644 --- a/strawberry_django/__init__.py +++ b/strawberry_django/__init__.py @@ -9,6 +9,7 @@ FilterLookup, RangeLookup, TimeFilterLookup, + GeometryFilterLookup, ) from .fields.types import ( DjangoFileType, @@ -48,6 +49,7 @@ "Ordering", "RangeLookup", "TimeFilterLookup", + "GeometryFilterLookup", "auth", "connection", "django_resolver", @@ -72,13 +74,3 @@ "relay", "type", ] - -from django.core.exceptions import ImproperlyConfigured - -try: - from .fields.filter_types import GeometryFilterLookup - - __all__.append("GeometryFilterLookup") -except ImproperlyConfigured: - # If gdal is not available, skip. - pass diff --git a/strawberry_django/fields/filter_types.py b/strawberry_django/fields/filter_types.py index bde5bbfa..4a12124e 100644 --- a/strawberry_django/fields/filter_types.py +++ b/strawberry_django/fields/filter_types.py @@ -131,6 +131,8 @@ class DatetimeFilterLookup(DateFilterLookup[T], TimeFilterLookup[T]): } +GeometryFilterLookup = None + try: pass except ImproperlyConfigured: diff --git a/strawberry_django/fields/types.py b/strawberry_django/fields/types.py index 89531371..555765ac 100644 --- a/strawberry_django/fields/types.py +++ b/strawberry_django/fields/types.py @@ -557,19 +557,8 @@ def resolve_model_field_type( and (field_type is not bool or not using_old_filters) ): if using_old_filters: - field_type = filters.FilterLookup[field_type] - elif type( - field_type - ) is ScalarWrapper and field_type._scalar_definition.name in ( - "Point", - "LineString", - "LinearRing", - "Polygon", - "MultiPoint", - "MultilineString", - "MultiPolygon", - "Geometry", - ): + field_type = filters.FilterLookup[field_type] # type: ignore + elif type(field_type) is ScalarWrapper and field_type._scalar_definition.name in ("Point", "LineString", "LinearRing", "Polygon", "MultiPoint", "MultilineString", "MultiPolygon", "Geometry"): field_type = filter_types.GeometryFilterLookup[field_type] else: field_type = filter_types.type_filter_map.get( # type: ignore diff --git a/tests/test_queries.py b/tests/test_queries.py index 1dea5bc7..00991318 100644 --- a/tests/test_queries.py +++ b/tests/test_queries.py @@ -8,6 +8,7 @@ from asgiref.sync import sync_to_async from django.core.files.uploadedfile import SimpleUploadedFile from django.test import override_settings +from django.conf import settings from graphql import GraphQLError from PIL import Image from strawberry import auto @@ -15,7 +16,7 @@ import strawberry_django from strawberry_django.settings import StrawberryDjangoSettings -from . import models, utils +from . import models, utils, types @pytest.fixture @@ -79,6 +80,8 @@ class Query: fruit: Fruit = strawberry_django.field() berries: list[BerryFruit] = strawberry_django.field() bananas: list[BananaFruit] = strawberry_django.field() + if settings.GEOS_IMPORTED: + geometries: list[types.GeoField] = strawberry_django.field() @pytest.fixture @@ -314,3 +317,18 @@ def fruit(self) -> Fruit: } """) assert result.data == {"fruit": {"colorId": mock.ANY, "name": "Banana"}} + + +@pytest.mark.skipif(not settings.GEOS_IMPORTED, reason="GeoDjango is not available.") +async def test_geos(query): + result = await query( + """ + query GeosQuery { + geometries { + geometry + } + } + """ + ) + + assert not result.errors diff --git a/tests/types.py b/tests/types.py index 42648a36..b714f8aa 100644 --- a/tests/types.py +++ b/tests/types.py @@ -47,6 +47,7 @@ class GeoField: multi_point: auto multi_line_string: auto multi_polygon: auto + geometry: auto @strawberry_django.input(models.GeosFieldsModel) class GeoFieldInput(GeoField): From e68b416d7eafadbcaad79b0109da0f3451b8f456 Mon Sep 17 00:00:00 2001 From: Evan Moon Date: Sun, 6 Apr 2025 20:44:22 +0900 Subject: [PATCH 09/10] Add filter to the test case --- tests/test_queries.py | 7 ++++--- tests/types.py | 6 +++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/test_queries.py b/tests/test_queries.py index 00991318..6a681bcf 100644 --- a/tests/test_queries.py +++ b/tests/test_queries.py @@ -321,14 +321,15 @@ def fruit(self) -> Fruit: @pytest.mark.skipif(not settings.GEOS_IMPORTED, reason="GeoDjango is not available.") async def test_geos(query): + from django.contrib.gis.geos import GEOSGeometry result = await query( """ - query GeosQuery { - geometries { + query GeosQuery($filter: GeoFieldFilter) { + geometries(filters: $filter) { geometry } } - """ + """, variable_values={"filter": {"geometry": {"contains": GEOSGeometry("POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))")}}} ) assert not result.errors diff --git a/tests/types.py b/tests/types.py index b714f8aa..bae717ea 100644 --- a/tests/types.py +++ b/tests/types.py @@ -38,7 +38,11 @@ class TomatoWithRequiredPictureType: if settings.GEOS_IMPORTED: - @strawberry_django.type(models.GeosFieldsModel) + @strawberry_django.filters.filter(models.GeosFieldsModel, lookups=True) + class GeoFieldFilter: + geometry: auto + + @strawberry_django.type(models.GeosFieldsModel, filters=GeoFieldFilter) class GeoField: id: auto point: auto From 2b1db9c76303f28fe1052a1a0dc4344a31d58bd4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 6 Apr 2025 11:46:32 +0000 Subject: [PATCH 10/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- strawberry_django/__init__.py | 4 ++-- strawberry_django/fields/types.py | 15 +++++++++++++-- tests/test_queries.py | 16 +++++++++++++--- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/strawberry_django/__init__.py b/strawberry_django/__init__.py index de298f56..45090c89 100644 --- a/strawberry_django/__init__.py +++ b/strawberry_django/__init__.py @@ -7,9 +7,9 @@ DateFilterLookup, DatetimeFilterLookup, FilterLookup, + GeometryFilterLookup, RangeLookup, TimeFilterLookup, - GeometryFilterLookup, ) from .fields.types import ( DjangoFileType, @@ -39,6 +39,7 @@ "DjangoModelType", "FilterLookup", "GeometryFilterLookup", + "GeometryFilterLookup", "ListInput", "ManyToManyInput", "ManyToOneInput", @@ -49,7 +50,6 @@ "Ordering", "RangeLookup", "TimeFilterLookup", - "GeometryFilterLookup", "auth", "connection", "django_resolver", diff --git a/strawberry_django/fields/types.py b/strawberry_django/fields/types.py index 555765ac..2fdbd324 100644 --- a/strawberry_django/fields/types.py +++ b/strawberry_django/fields/types.py @@ -557,8 +557,19 @@ def resolve_model_field_type( and (field_type is not bool or not using_old_filters) ): if using_old_filters: - field_type = filters.FilterLookup[field_type] # type: ignore - elif type(field_type) is ScalarWrapper and field_type._scalar_definition.name in ("Point", "LineString", "LinearRing", "Polygon", "MultiPoint", "MultilineString", "MultiPolygon", "Geometry"): + field_type = filters.FilterLookup[field_type] # type: ignore + elif type( + field_type + ) is ScalarWrapper and field_type._scalar_definition.name in ( + "Point", + "LineString", + "LinearRing", + "Polygon", + "MultiPoint", + "MultilineString", + "MultiPolygon", + "Geometry", + ): field_type = filter_types.GeometryFilterLookup[field_type] else: field_type = filter_types.type_filter_map.get( # type: ignore diff --git a/tests/test_queries.py b/tests/test_queries.py index 6a681bcf..7aa760cf 100644 --- a/tests/test_queries.py +++ b/tests/test_queries.py @@ -6,9 +6,9 @@ import pytest import strawberry from asgiref.sync import sync_to_async +from django.conf import settings from django.core.files.uploadedfile import SimpleUploadedFile from django.test import override_settings -from django.conf import settings from graphql import GraphQLError from PIL import Image from strawberry import auto @@ -16,7 +16,7 @@ import strawberry_django from strawberry_django.settings import StrawberryDjangoSettings -from . import models, utils, types +from . import models, types, utils @pytest.fixture @@ -322,6 +322,7 @@ def fruit(self) -> Fruit: @pytest.mark.skipif(not settings.GEOS_IMPORTED, reason="GeoDjango is not available.") async def test_geos(query): from django.contrib.gis.geos import GEOSGeometry + result = await query( """ query GeosQuery($filter: GeoFieldFilter) { @@ -329,7 +330,16 @@ async def test_geos(query): geometry } } - """, variable_values={"filter": {"geometry": {"contains": GEOSGeometry("POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))")}}} + """, + variable_values={ + "filter": { + "geometry": { + "contains": GEOSGeometry( + "POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))" + ) + } + } + }, ) assert not result.errors