TransWikia.com

Load multipolygons from GeoJSON into GeoDjango model

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.

2 Answers

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

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP