Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Geonode -> Django 2.2 x GDAL 3 #8502

Closed
cmotadev opened this issue Dec 16, 2021 · 2 comments
Closed

Geonode -> Django 2.2 x GDAL 3 #8502

cmotadev opened this issue Dec 16, 2021 · 2 comments

Comments

@cmotadev
Copy link

Hi @afabiani and other colleagues

We are developing a plugin for GeoNode, running on Docker, that uses geonode-project and we are experiencing some issues. We have a django model that uses a GeometryField and the model saves geometry with flipped coordinates.

I checked that Geonode uses Django 2.2.x, which GDAL requirements are up to 2.3.x, and in the dockerfile it brings GDAL 3. I think it's a Django behavior than Geonode itself, but I think that it's crucial for setting the geonode requierements - GDAL 3 changed the default behavior of coordinate transformation

There is a ticket into the Django Project that issues this problem.

My suggestion is to put GDAL 2.X as default, or adopt Django 3.1.x as default, which one is easier :)

Thanks for appreciate.

Expected Behavior

GeoDjango saves the geometry as is

Actual Behavior

GeoDjango is flipping the geometry's coordinates

Steps to Reproduce the Problem

  1. Create a Django geonode project
  2. Create a spatial model using geodjango
  3. Fill the model props and save it to db.

Specifications

  • GeoNode version: 3.2.1
  • Installation method (manual, GeoNode Docker, SPCGeoNode Docker): GeoNode Docker
  • Platform: Linux
  • Additional details:
@afabiani
Copy link
Member

@cmotadev currently only master is using Django==3.2.* the older branches are still using Django 2.*

As far as I remember we used this checks in order to deal with the GDAL 3 coordinate flipping issue

https://github.com/GeoNode/geonode/blob/3.2.x/geonode/utils.py#L398

Maybe this one could work for you too?

@cmotadev
Copy link
Author

cmotadev commented Dec 17, 2021

@afabiani I checked your suggestion and doesn't work for me, but your implementation gived me an idea: The main problem is because the GeoDjango implementation doesn't use pyGDAL. The bindings are done directly on the library.

I solved my problem subclassing the GeometryField to flip coordinates before saving into DB and after retrieve on it. I used Shapely to make the things easier.

# models.py
from django.contrib.gis.db.models import MultiPolygonField as BaseMultiPolygonField
from django.contrib.gis.geos import GEOSGeometry
from django.db import models
from osgeo.gdal import __version__ as version 
from shapely.wkb import loads
from shapely.ops import transform


class MultiPolygonField(BaseMultiPolygonField):
    gdal_version = int(version.split(".")[0])

    def _fix_gdal_axis_error(self, geom):
        if self.gdal_version >= 3:
            _g = transform(lambda x, y: (y, x), loads(bytes(geom.wkb)))
            wkb = _g.wkb_hex
            srid = geom.srs.srid
        
            geom = GEOSGeometry(wkb, srid=srid)
        
        return geom
    
    def to_python(self, value):
        _value = super().to_python(value)
        return self._fix_gdal_axis_error(_value)

    def from_db_value(self, value, expression, connection):
        if value is None:
            return value

        return self._fix_gdal_axis_error(value)

# Create your models here.
class SpatialModel(models.Model):
    name = models.CharField(
        max_length=255
    )

    shape = MultiPolygonField(
        srid=4674
    )

    def __str__(self):
        return self.name

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants