Skip to content

Commit

Permalink
Added envvars for ports; Added geojson calculated in DB
Browse files Browse the repository at this point in the history
  • Loading branch information
suricactus authored and 3nids committed Sep 28, 2023
1 parent 0aa85dd commit c534f6a
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 24 deletions.
25 changes: 24 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@ OGCAPIF_HOST=localhost
# Change this to some long and random sequence
DJANGO_SECRET_KEY=_change_me_

# Customize the postgres superuser password
# Postgres connection settings
POSTGRES_USER=postgres
POSTGRES_PASSWORD=_change_me_
POSTGRES_DB=postgres
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
# SSL mode. Most of the times should be either "prefer" OR "require". Default: "prefer"
POSTGRES_SSLMODE=prefer

# Transifex token, required to pull translations
TX_TOKEN=_change_me_
Expand All @@ -20,3 +26,20 @@ GEOMETRY_SRID=2056

# (cross-platform compatibility, do not change)
COMPOSE_FILE_SEPARATOR=:

# The Django development port. Not used in production.
# DEFAULT: 7180
DJANGO_DEV_PORT=7180

# The Django development port. Not used in production.
# DEFAULT: 7178
DEBUGPY_PORT=7178

# Caddy HTTP port. Default: 80
WEB_HTTP_PORT=80

# Caddy HTTPS port. Default: 443
WEB_HTTPS_PORT=443

# Postgres port on the host. Not used in production. Default: 7132
HOST_POSTGRES_PORT=7132
6 changes: 3 additions & 3 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ services:
- ./unit_tests_outputs/:/unit_tests_outputs
ports:
# making django directly accessible for debugging
- 8000:8000
- ${DJANGO_DEV_PORT:?}:8000
# debugpy
- 5678:5678
- ${DEBUGPY_PORT:?}:5678
command: python3 -m debugpy --listen 0.0.0.0:5678 manage.py runserver 0.0.0.0:8000

postgres:
ports:
- 5432:5432
- ${HOST_POSTGRES_PORT:?}:5432
13 changes: 9 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ services:
environment:
OGCAPIF_HOST: ${OGCAPIF_HOST:?}
ports:
- 80:80
- 443:443
- ${WEB_HTTP_PORT:?}:80
- ${WEB_HTTPS_PORT:?}:443

django:
image: opengisch/django-oapif:latest
Expand All @@ -40,23 +40,28 @@ services:
DJANGO_STATIC_ROOT: /static_volume
DJANGO_MEDIA_ROOT: /media_volume
GEOMETRY_SRID: ${GEOMETRY_SRID:-2056}
POSTGRES_USER: ${POSTGRES_USER:?}
POSTGRES_DB: ${POSTGRES_DB:?}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?}
POSTGRES_HOST: ${POSTGRES_HOST:?}
POSTGRES_PORT: ${POSTGRES_PORT:?}
POSTGRES_SSLMODE: ${POSTGRES_SSLMODE:?}
TX_TOKEN: ${TX_TOKEN}
command: python3 manage.py runserver 0.0.0.0:8000

postgres:
image: postgis/postgis:13-3.1
environment:
POSTGRES_USER: ${POSTGRES_USER:?}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?}
POSTGRES_DB: ${POSTGRES_DB:?}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
# If you need the database to be accessible from the host
# uncomment the two lines below
# ports:
# - "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data

Expand Down
64 changes: 54 additions & 10 deletions src/django_oapif/decorators.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
from typing import Any, Callable, Dict, Optional

from django.db.models import Model
from rest_framework import viewsets
from django.db import models
from django.db.models.functions import Cast
from rest_framework import serializers, viewsets
from rest_framework.serializers import ModelSerializer
from rest_framework_gis.serializers import GeoFeatureModelSerializer

from django_oapif.metadata import OAPIFMetadata
from django_oapif.mixins import OAPIFDescribeModelViewSetMixin
from django_oapif.urls import oapif_router

from .filters import BboxFilterBackend
from .functions import AsGeoJSON

USE_PG_GEOJSON = False
USE_PG_GEOJSON = True


def register_oapif_viewset(
key: Optional[str] = None,
skip_geom: Optional[bool] = False,
custom_serializer_attrs: Dict[str, Any] = None,
custom_viewset_attrs: Dict[str, Any] = None,
) -> Callable[[Any], Model]:
) -> Callable[[Any], models.Model]:
"""
This decorator takes care of all boilerplate code (creating a serializer, a viewset and registering it) to register
a model to the default OAPIF endpoint.
Expand Down Expand Up @@ -47,13 +53,37 @@ def inner(Model):
_viewset_oapif_geom_lookup = None
_geo_field = None

class AutoSerializer(GeoFeatureModelSerializer):
class Meta:
nonlocal _geo_field

model = Model
fields = "__all__"
geo_field = _geo_field
if USE_PG_GEOJSON:

class AutoSerializer(ModelSerializer):
geojson = serializers.JSONField()

class Meta:
model = Model
fields = [
"id",
"geojson",
"field_0",
"field_1",
"field_2",
"field_3",
"field_4",
"field_5",
"field_6",
"field_7",
"field_8",
"field_9",
]

else:

class AutoSerializer(GeoFeatureModelSerializer):
class Meta:
nonlocal _geo_field

model = Model
fields = "__all__"
geo_field = _geo_field

# Create the viewset
class Viewset(OAPIFDescribeModelViewSetMixin, viewsets.ModelViewSet):
Expand Down Expand Up @@ -84,6 +114,20 @@ def finalize_response(self, request, response, *args, **kwargs):
response.headers["Allow"] = allowed_actions
return response

def get_queryset(self):
qs = super().get_queryset()

if USE_PG_GEOJSON:
# NOTE the defer should not be needed, as the field should be skipped already when we define `Serializer.Meta.Fields` without the `geom` col
qs = qs.defer("geom")
qs = qs.annotate(
geojson=Cast(
AsGeoJSON("geom", False, False), models.JSONField()
)
)

return qs

# Apply custom serializer attributes
for k, v in custom_serializer_attrs.items():
setattr(AutoSerializer.Meta, k, v)
Expand Down
20 changes: 20 additions & 0 deletions src/django_oapif/functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from django.contrib.gis.db.models import functions
from django.db import models


class AsGeoJSON(functions.AsGeoJSON):
output_field = models.TextField()

def __init__(self, expression, bbox=False, crs=False, precision=8, **extra):
expressions = [expression]
if precision is not None:
expressions.append(self._handle_param(precision, "precision", int))
options = 0
if crs and bbox:
options = 3
elif bbox:
options = 1
elif crs:
options = 2
expressions.append(options)
super().__init__(*expressions, **extra)
13 changes: 11 additions & 2 deletions src/django_oapif/pagination.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.http import HttpResponse
from rest_framework import pagination
from rest_framework.response import Response
from rest_framework.utils.serializer_helpers import ReturnList


class OapifPagination(pagination.LimitOffsetPagination):
Expand All @@ -9,6 +10,14 @@ class OapifPagination(pagination.LimitOffsetPagination):
default_limit = 1000

def get_paginated_response(self, data):
if isinstance(data, ReturnList):
number_returned = len(data)

extra_params = {"features": [*data]}
else:
number_returned = len(data["features"])
extra_params = {**data}

return Response(
{
"links": [
Expand All @@ -25,9 +34,9 @@ def get_paginated_response(self, data):
"href": self.get_previous_link(),
},
],
"numberReturned": len(data["features"]),
"numberReturned": number_returned,
"numberMatched": self.count,
**data,
**extra_params,
}
)

Expand Down
8 changes: 4 additions & 4 deletions src/tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@
DATABASES = {
"default": {
"ENGINE": "django.contrib.gis.db.backends.postgis",
"NAME": "postgres",
"HOST": "postgres",
"PORT": 5432,
"USER": "postgres",
"NAME": os.getenv("POSTGRES_DB"),
"HOST": os.getenv("POSTGRES_HOST"),
"PORT": os.getenv("POSTGRES_PORT"),
"USER": os.getenv("POSTGRES_USER"),
"PASSWORD": os.getenv("POSTGRES_PASSWORD"),
}
}
Expand Down
Empty file removed src/tests/views.py
Empty file.

0 comments on commit c534f6a

Please sign in to comment.