From b09e047f6a55d902e49440b7bd9c97df400f9cd9 Mon Sep 17 00:00:00 2001 From: Adrien Date: Mon, 12 Jun 2023 09:07:09 +0200 Subject: [PATCH] Cleaning up (#82) --- .gitignore | 1 + .vscode/launch.json | 21 ------ .vscode/settings.json | 3 - pyproject.toml | 3 +- requirements.txt | 2 +- src/django_oapif/decorators.py | 66 +++++-------------- src/django_oapif/filters.py | 23 +++++-- src/django_oapif/pagination.py | 2 +- src/django_oapif/routers.py | 1 - src/signalo/core/models.py | 4 ++ src/signalo/core/views.py | 1 - .../management/commands/populate_roads.py | 2 +- 12 files changed, 46 insertions(+), 83 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index eade310c..b3603977 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ src/django_oapif/__version__.py static media _test_outputs +.vscode/ diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index aed556d2..00000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Python: Remote Attach", - "type": "python", - "request": "attach", - "connect": { - "host": "localhost", - "port": 5678 - }, - "pathMappings": [ - { - "localRoot": "${workspaceFolder}/src", - "remoteRoot": "." - } - ], - "justMyCode": true - } - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 738281aa..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.analysis.typeCheckingMode": "off" -} diff --git a/pyproject.toml b/pyproject.toml index c5ae2640..6e300abf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,6 +3,7 @@ requires = ["setuptools>=45", "setuptools_scm[toml]==7.*"] build-backend = "setuptools.build_meta" [project] +requires-python = ">=3.9" name = "django-ogcapif" authors = [ {name = "OPENGIS.ch", email = "info@opengis.ch"}, @@ -30,4 +31,4 @@ root = ".." [tool.setuptools.dynamic] readme = {file = ["README.md"], content-type = "text/markdown"} dependencies = {file = ["requirements.txt"]} -optional-dependencies.dev = {file = ["requirements-dev.txt"]} +optional-dependencies = {file = ["requirements-dev.txt"]} diff --git a/requirements.txt b/requirements.txt index 7a2e04d9..19df5b6f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ django>=4 django-computedfields -psycopg2 +psycopg2-binary transifex-client djangorestframework djangorestframework-gis diff --git a/src/django_oapif/decorators.py b/src/django_oapif/decorators.py index 78048fa2..36e3213e 100644 --- a/src/django_oapif/decorators.py +++ b/src/django_oapif/decorators.py @@ -1,17 +1,12 @@ -from os import getenv from typing import Any, Callable, Dict, Optional -from django.contrib.gis.geos import Polygon from django.db.models import Model -from django.http import HttpResponseBadRequest -from pyproj import CRS, Transformer from rest_framework import viewsets from rest_framework_gis.serializers import GeoFeatureModelSerializer from django_oapif.mixins import OAPIFDescribeModelViewSetMixin from django_oapif.urls import oapif_router -from .crs_utils import get_crs_from_uri from .filters import BboxFilterBackend @@ -49,16 +44,17 @@ class Meta: fields = "__all__" geo_field = "geom" - """ ON HOLD, WAITING ON GeoFeatureModelSerializer to admit of null geometries """ - # class AutoNoGeomSerializer(ModelSerializer): - # class Meta: - # model = Model - # fields = "__all__" - - # if skip_geom: - # viewset_serializer_class = AutoNoGeomSerializer - # viewset_oapif_geom_lookup = None - # else: + # ON HOLD, WAITING ON GeoFeatureModelSerializer to admit of null geometries + """ + class AutoNoGeomSerializer(ModelSerializer): + class Meta: + model = Model + fields = "__all__ + if skip_geom: + viewset_serializer_class = AutoNoGeomSerializer + viewset_oapif_geom_lookup = None + else: + """ viewset_serializer_class = AutoSerializer viewset_oapif_geom_lookup = ( "geom" # one day this will be retrieved automatically from the serializer @@ -80,41 +76,13 @@ class Viewset(OAPIFDescribeModelViewSetMixin, viewsets.ModelViewSet): # Allowing '.' and '-' in urls lookup_value_regex = r"[\w.-]+" - def get_queryset(self): - # Override get_queryset to catch bbox-crs - queryset = super().get_queryset() - - if self.request.GET.get("bbox"): - coords = self.request.GET["bbox"].split(",") - user_crs = self.request.GET.get("bbox-crs") - - if user_crs: - try: - user_crs = get_crs_from_uri(user_crs) - except: - return HttpResponseBadRequest( - "This API supports only EPSG-specified CRS. Make sure to use the appropriate value for the `bbox-crs`query parameter." - ) - api_crs = CRS.from_epsg(int(getenv("GEOMETRY_SRID", "2056"))) - transformer = Transformer.from_crs(user_crs, api_crs) - LL = transformer.transform(coords[0], coords[1]) - UR = transformer.transform(coords[2], coords[3]) - my_bbox_polygon = Polygon.from_bbox( - [LL[0], LL[1], UR[0], UR[1]] - ) - - else: - my_bbox_polygon = Polygon.from_bbox(coords) - - return queryset.filter(geom__intersects=my_bbox_polygon) - - return queryset.all() - + # ON HOLD, WAITING ON GeoFeatureModelSerializer to admit of null geometries + """ # Apply custom serializer attributes - # if viewset_serializer_class.__name__ == "AutoNoGeomSerializer": - # for k, v in custom_serializer_attrs.items(): - # setattr(AutoNoGeomSerializer.Meta, k, v) - + if viewset_serializer_class.__name__ == "AutoNoGeomSerializer": + for k, v in custom_serializer_attrs.items(): + setattr(AutoNoGeomSerializer.Meta, k, v) + """ # Apply custom serializer attributes for k, v in custom_serializer_attrs.items(): setattr(AutoSerializer.Meta, k, v) diff --git a/src/django_oapif/filters.py b/src/django_oapif/filters.py index 05cc60b2..17793f79 100644 --- a/src/django_oapif/filters.py +++ b/src/django_oapif/filters.py @@ -1,6 +1,11 @@ +from os import getenv + from django.contrib.gis.geos import Polygon +from pyproj import CRS, Transformer from rest_framework.filters import BaseFilterBackend +from .crs_utils import get_crs_from_uri + # Adapted from rest_framework_gis.filters.InBBoxFilter class BboxFilterBackend(BaseFilterBackend): @@ -9,10 +14,20 @@ def filter_queryset(self, request, queryset, view): if not bbox_string: return queryset - p1x, p1y, p2x, p2y = (float(n) for n in bbox_string.split(",")) - # TODO: take into account bbox-crs which may differ from the geom - bbox = Polygon.from_bbox((p1x, p1y, p2x, p2y)) - # TODO: geom shouldn't be hardcoded here + coords = tuple(float(n) for n in bbox_string.split(",")) + user_crs = request.query_params.get("bbox-crs") + + if user_crs: + user_crs = get_crs_from_uri(user_crs) + api_crs = CRS.from_epsg(int(getenv("GEOMETRY_SRID", "2056"))) + transformer = Transformer.from_crs(user_crs, api_crs) + LL = transformer.transform(coords[0], coords[1]) + UR = transformer.transform(coords[2], coords[3]) + bbox = Polygon.from_bbox([LL[0], LL[1], UR[0], UR[1]]) + + else: + bbox = Polygon.from_bbox(coords) + return queryset.filter(geom__bboverlaps=bbox) def get_schema_operation_parameters(self, view): diff --git a/src/django_oapif/pagination.py b/src/django_oapif/pagination.py index 4193ddea..04c55f67 100644 --- a/src/django_oapif/pagination.py +++ b/src/django_oapif/pagination.py @@ -25,7 +25,7 @@ def get_paginated_response(self, data): ], "numberReturned": len(data["features"]), "numberMatched": self.count, - **data, # this looks to be unpacked by LimitOffsetPagination anyway + **data, } ) diff --git a/src/django_oapif/routers.py b/src/django_oapif/routers.py index 82eb2126..9924c465 100644 --- a/src/django_oapif/routers.py +++ b/src/django_oapif/routers.py @@ -19,7 +19,6 @@ class OAPIFRouter(routers.SimpleRouter): """ include_format_suffixes = True - # default_schema_renderers = None APISchemaView = SchemaView SchemaGenerator = SchemaGenerator diff --git a/src/signalo/core/models.py b/src/signalo/core/models.py index 6cea23b1..0adb19d4 100644 --- a/src/signalo/core/models.py +++ b/src/signalo/core/models.py @@ -102,6 +102,10 @@ def geom(self): ], ) def offset_px(self) -> int: + """ + Recalculates offset whenever a new Sign instance + occurs on the same pole + """ default_padding_px = 5 previous_signs_on_pole = Sign.objects.filter( azimuth__pole__id=self.azimuth.pole.id, order__lt=self.order diff --git a/src/signalo/core/views.py b/src/signalo/core/views.py index 54397c16..b09b9181 100644 --- a/src/signalo/core/views.py +++ b/src/signalo/core/views.py @@ -32,7 +32,6 @@ class PoleHighPerfViewset(OAPIFDescribeModelViewSetMixin, viewsets.ModelViewSet) pagination_class = HighPerfPagination oapif_title = "Poles (high perf)" oapif_description = "Poles layer - including high performance optimization" - # (one day this will be retrieved automatically from the serializer) oapif_geom_lookup = "geom" def list(self, request, *args, **kwargs): diff --git a/src/signalo/roads/management/commands/populate_roads.py b/src/signalo/roads/management/commands/populate_roads.py index c1eec868..46a04edd 100644 --- a/src/signalo/roads/management/commands/populate_roads.py +++ b/src/signalo/roads/management/commands/populate_roads.py @@ -36,7 +36,7 @@ def handle(self, *args, **kwargs): if batch: Road.objects.bulk_create(batch) len_batch = len(batch) - total += len(batch) + total += len_batch print(f"{len_batch} more roads...") else: break