Sunday, 10 September 2017

postgis - Update GeoDjango models from KML?


I'm working in Django 1.9 and Postgres 9.4 with PostGIS extensions. I have a KML file, and I want to use it to update my geo fields. This is my model:


class PCT(models.Model):
code = models.CharField(max_length=3, primary_key=True)
boundary = models.GeometryField(null=True, blank=True)
objects = models.GeoManager()

This is my current code:


    from django.contrib.gis.gdal import DataSource
from django.contrib.gis.utils import LayerMapping

ds = DataSource(options['filename'])
layer_mapping = {
'code': 'Name',
'boundary': 'Unknown'
}
lm = LayerMapping(PCT, options['filename'],
layer_mapping, transform=False) # , unique='code')
lm.save(strict=True)

It works OK, but if I run it a second time, it won't update any existing PCT fields - instead it creates new ones. This is a problem when I want to update the boundaries. (I can't just delete and re-create the fields, because there are foreign key dependencies.)



How can I use my KML file to update existing files?


@alex suggested trying this, but I'm getting an error:


    ds = DataSource(options['filename'])
for layer in ds:
for i in layer:
code = str(i['Name'])
geom = i.geom
print geom

geos_geom = geom.geos

print geos_geom

boundary = GEOSGeometry(geom)
print boundary

pct = PCT.objects.get(code=code)
if pct:
pct.boundary = geos_geom
pct.save()


This throws an error at the boundary = GEOSGeometry(geom) line: TypeError: Improper geometry input type: .


The output from the print statements up to that point is as follows:


POLYGON ((-1.407325 54.593612 0,-1.423288 54.603131 0,-1.431455 54.595297 0 ...
SRID=4326;POLYGON Z ((-1.4073249999999999 54.5936120000000003 0.0000000000000000

What am I doing wrong?


I tried simply passing a string to GEOSGeometry:


boundary = GEOSGeometry(str(i.geom))
pct = PCT.objects.get(code=code)
if pct:

pct.boundary = boundary
pct.save()

Perhaps this solves the issue? But now I get a different error on pct.save():


django.db.utils.DataError: Geometry has Z dimension but column does not

I can see by looking at the print statements that there is indeed a z column, but it's always zero, is it possible to get rid of this somehow?



Answer



There is indeed no need to use LayerMapping here: I can't test this right now so it may be bugged, but the idea is to test if your object exists first, and if it does, update the geometry.


from django.contrib.gis.gdal import DataSource

from django.contrib.gis.geos import GEOSGeometry


def update_pct():
source = DataSource('some/path/to/the/file.kml')
for layer in source:
for feat in layer:
code = feat['code'].value
geom = feat.get_geoms() # Get the feature geometry.
geos_geom = geom.geos # Get the geos representation of the geometry.

boundary = GEOSGeometry(geom) # Make a GeosGeometry object using the string representation.

pct = PCT.objects.get(code=code) # Note that .get() raises a DoesNotExist error if the object doesn't exist, so you will have to catch this.
pct.boundary = boundary
pct.save()

You probably also want to store details about when PCTs are updated somewhere.


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...