Skip to content

Commit

Permalink
Merge pull request #1395 from open-zaak/issue/1060-admin-map-widget
Browse files Browse the repository at this point in the history
show map in the admin for Zaak.zaakgeometrie
  • Loading branch information
annashamray committed Jul 10, 2023
2 parents ccb1b02 + 7ca7c77 commit a289041
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/openzaak/components/zaken/admin/zaken.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
# Copyright (C) 2019 - 2022 Dimpact
from django import forms
from django.contrib import admin
from django.contrib.gis.admin import OSMGeoAdmin
from django.db.models import CharField, F
from django.db.models.functions import Concat

from openzaak.forms.widgets import AuthorityAxisOrderOLWidget
from openzaak.utils.admin import (
AuditTrailAdminMixin,
EditInlineAdminMixin,
Expand Down Expand Up @@ -599,7 +601,7 @@ def clean(self):

@admin.register(Zaak)
class ZaakAdmin(
AuditTrailAdminMixin, ListObjectActionsAdminMixin, UUIDAdminMixin, admin.ModelAdmin
AuditTrailAdminMixin, ListObjectActionsAdminMixin, UUIDAdminMixin, OSMGeoAdmin
):
list_display = (
"identificatie",
Expand Down Expand Up @@ -634,6 +636,7 @@ class ZaakAdmin(
]
raw_id_fields = ("_zaaktype", "hoofdzaak", "_zaaktype_base_url")
viewset = "openzaak.components.zaken.api.viewsets.ZaakViewSet"
widget = AuthorityAxisOrderOLWidget

def get_object_actions(self, obj):
return (
Expand Down
54 changes: 54 additions & 0 deletions src/openzaak/forms/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
from typing import Optional, Union

from django import forms
from django.contrib.gis.admin.widgets import OpenLayersWidget
from django.contrib.gis.gdal import AxisOrder, OGRGeometry, SpatialReference
from django.contrib.gis.geos import GEOSGeometry
from django.utils.translation import ugettext_lazy as _

from dateutil.relativedelta import relativedelta
Expand Down Expand Up @@ -141,3 +144,54 @@ def _build_subwidget_context(
name=f"{name}_{attribute}", value=value, attrs=attrs,
)
return widget_context["widget"]


class AuthoritySpatialReference(SpatialReference):
def __init__(self, srs_input="", srs_type="user"):
super().__init__(srs_input, srs_type, axis_order=AxisOrder.AUTHORITY)


class AuthorityAxisOrderOLWidget(OpenLayersWidget):
"""
Here is a long and painful explanation why we need it. Buckle up.
First, `Zaak.zaakgeometry` field is geometric field, not geographic. If it's a point, it has x and y coordinates.
But how do we map them to lat and lon? What is the order - lat/lon or lon/lat?
Well, there is no consensus what should be the order.
OpenZaak supports only "ESPG:4326" coordinate system. According to "ESPG:4326" it should be lat/lon order.
GDAL<3.0 expects lon/lat order and treat all points like lon/lat.
Good news, that GDAL>=3.0 can use the order defined in CRS. And in Open Zaak we support GDAL >= 3.0
BUT django.contrib.gis.gdal uses traditional axis order (lon/lat) as a default one and user can set up only
SRID without axis order when initializing geometry objects.
OpenStreetMap supports "ESPG:3587" coordinate system. So in the parent class "ESPG:4326" coordinates are
transformed to "ESPG:3587" using GDAL api with traditional axis order, where 'x' is treated as 'lon'
and 'y' is treated as 'lat'
In this class we transform coordinates with "Authority" order, for "ESPG:4326" it's lat/lon.
If in next django versions "axis_order" is treated with more attention, this workaround should be removed.
This workaround won't work if os GDAL<3.0. Perhaps, in this case we can use django-leaflet?
GDAL related doc - https://gdal.org/tutorials/osr_api_tut.html#crs-and-axis-order
"""

data_srid = 4326

def get_context(self, name, value, attrs):
if value:
ogr = OGRGeometry(value.wkt, AuthoritySpatialReference(value.srid))
# ogr = value.ogr
ogr.transform(self.params["srid"])
value = GEOSGeometry(ogr._geos_ptr(), srid=ogr.srid)

return super().get_context(name, value, attrs)

def deserialize(self, value):
value = GEOSGeometry(value)

if value.srid and value.srid != self.data_srid:
value.transform(AuthoritySpatialReference(self.data_srid))
return value

0 comments on commit a289041

Please sign in to comment.