2

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.

2 Answers 2

6

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.

2
  • I put this project on hold for now but will revisit it at some point and let you know if this works. Thanks for the suggestion.
    – its30
    Commented Feb 28, 2019 at 21:10
  • 1
    I think you could also create a Multipolygon directly no? E.g. feature.geom = MultiPolygon(feature.geom)
    – Alexander
    Commented Mar 14, 2019 at 9:57
4

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)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.