Generalizing Polygons to MultiPolygons in GeoDjango?

The SQL to drop the constraint:

ALTER TABLE myapp_mymodel DROP CONSTRAINT enforce_geotype_mygeom;

Or to alter it to allow both Polygons & MultiPolygons:

ALTER TABLE myapp_mymodel DROP CONSTRAINT enforce_geotype_mygeom;
ALTER TABLE myapp_mymodel ADD CONSTRAINT enforce_geotype_mygeom CHECK (geometrytype(mygeom) = 'POLYGON'::text OR geometrytype(mygeom) = 'MULTIPOLYGON'::text OR mygeom IS NULL);

These SQL statements could be run from a South migration or an initial-data SQL script.

Another option is to make it a GeometryField in your Django model definition - this will allow it to store any geometry type.

Or, override the save() method on your model to force everything to be a MultiPolygon:

from django.contrib.gis.db import models
from django.contrib.gis import geos

class MyModel(models.Model):
  mygeom = models.MultiPolygonField()
  ... other fields....

  def save(self, *args, **kwargs):
    # if mygeom ends up as a Polgon, make it into a MultiPolygon
    if self.mygeom and isinstance(self.mygeom, geos.Polygon):
      self.mygeom = geos.MultiPolygon(self.mygeom)

    super(MyModel).save(*args, **kwargs)

I know this is old, but I just ran into this issue myself and had problems using the above suggested solutions:

  • Using GeometryField makes it difficult to use the built-in OSMGeoAdmin class. The code in templates/gis/admin/openlayers.js (and contrib/gis/admin/widgets.py and probably other places I missed) frequently assumes that the geometry is a point, line, polygon, or collection, and never accounts for generic geometries. This isn't necessarily important or insurmountable, but if you were planning on using the built-in admin you might be disappointed.

  • Overriding save() doesn't work because the type-checking happens sooner, in the model's __set__().

My current solution is explicitly coercing all of my Polygons into MultiPolygons when importing and saving my data. I might override __set__() if this becomes cumbersome.


longish workaround

one could use fromstr()

from django.contrib.gis.geos import fromstr

p = Polygon()
# this seems to work correctly
mp = MultiPolygon(fromstr(str(p)),)

model1.geom_field = mp

model1.save()