Geographic Information Systems Asked on June 28, 2021
I have a simple model:
from django.contrib.gis.db import models
class CountryShapes(models.Model):
geonameid = models.PositiveIntegerField(primary_key=True)
geom = models.MultiPolygonField()
and a GeoJSON file from here:
http://download.geonames.org/export/dump/shapes_simplified_low.json.zip
I am attempting to load the data into my model using this:
import json
from django.contrib.gis.geos import GEOSGeometry
with open('shapes_simplified_low.json', 'r') as fd:
data = json.load(fd)
for feature in data['features']:
geom = GEOSGeometry(str(feature['geometry']))
geonameid = feature['properties']['geoNameId']
country = CountryShapes( # throws error here
geonameid=geonameid,
geom=GEOSGeometry(geom))
country.save()
and I get this error:
TypeError: Cannot set CountryShapes SpatialProxy (MULTIPOLYGON) with
value of type: class ‘django.contrib.gis.geos.polygon.Polygon’
GEOSGeometry
seems to create the geometry fine, its when I pass the geom
argument to my model it throws the error.
The issue: You're trying to save a feature of type 'Polygon' to a field defined for MultiPolygons. (You'll notice a list of geojson features often have both Polygons and MultiPolygons.)
I'm using this hack: If a feature is type Polygon, change it to type MultiPolygon by changing type and putting the coordinates within an array.
geom = GEOSGeometry(str(feature['geometry']))
if geom.type == 'Polygon':
geom['type'] = 'MultiPolygon'
geom['coordinates'] = [feature['geometry']['coordinates']]
geonameid = feature['properties']['geoNameId']
country = CountryShapes( # throws error here
geonameid=geonameid,
geom=GEOSGeometry(geom))
country.save()
PS: I have almost no experience in Python.
Answered by Mike Fabrikant on June 28, 2021
You are getting this error because the geometry type in the json file is of type "Polygon" and the Django geometry field is MultiPolygon. So we have to create a Polygon GEOSGeometry and promote it to a GEOS MultiPolygon. See snippet below.
I have omitted inserting the "geonameid" from the json into the model because it is a primary key. If you want to keep geonameid it would probably be best to have geonameid as a new field and let django handle the primary key.
I also threw a try-except in there to handle the possibility of other geometry types and allow all of the acceptable geometries to be processed.
import json
from django.contrib.gis.geos import GEOSGeometry, Polygon, MultiPolygon
from appname.models import CountryShapes
with open('shapes_simplified_low.json') as f:
data = json.load(f)
for ft in data['features']:
geom_str = json.dumps(ft['geometry'])
geom = GEOSGeometry(geom_str)
try:
if isinstance(geom, MultiPolygon):
continue
elif isinstance(geom, Polygon):
geom = MultiPolygon([geom])
else:
raise TypeError(
'{} not acceptable for this model'.format(geom.geom_type)
)
country = CountryShapes(geom=geom)
country.save()
except TypeError as e:
print(e)
Answered by kingurr on June 28, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP