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