Search code examples
djangopostgis

OSMGeoAdmin: Imported OSM maps: points, lines and roads are ok, not multipolygons


  • Download an OSM map from geofabrik.
  • Import it with osm2pgsql (basic commands, no fancy stuff)

You will have your tables ready to use.

Here's are my models (all the same fields for Line, Polygon, Point and Roads, just one is enough):

class PlanetOsmLine(models.Model):
    class Meta:
        db_table = 'planet_osm_line'
        managed = False

    osm_id = models.BigIntegerField(primary_key=True)
    # ...tons of other field (unused)...
    way = GeometryField(default=None)

Now, to display it in the admin interface, basic admin.ModelAdmin does the job and it work, like this for a road:

basic admin display

Let's add the OSMGeoAdmin interface with this code:

class PlanetOsmAdmin(OSMGeoAdmin):
    pass

my_admin_site.register(PlanetOsmLine, PlanetOsmAdmin)
my_admin_site.register(PlanetOsmPolygon, PlanetOsmAdmin)
my_admin_site.register(PlanetOsmPoint, PlanetOsmAdmin)
my_admin_site.register(PlanetOsmRoads, PlanetOsmAdmin)

You'll get this, which is way nicer:

osmgeoadmin admin display

OSM Admin works with everything except polygons. Here's the basic view:

polygons basic admin interface

And when I do my_admin_site.register(PlanetOsmPolygon, PlanetOsmAdmin) then I get only this, always the same place:

problematic polygons OSM admin interface

If the polygons are displayed properly without OSMGeoAdmin, and are not displayed properly with it. There's no error in the console log of Chrome.

What am I missing?


Solution

  • Ok I found the problem. You can override some values in OSMGeoAdmin, and setting display_wkt to True showed me it was empty.

    class PlanetOsmAdmin(OSMGeoAdmin):
        display_wkt = True
    

    So I did a step-by-step debugging and found out that my value for polygons are:

    SRID=3857;POLYGON ((5024019.9 -1441890.9, ..., 5024019.9 -1441890.690534543))
    

    In the source code (/Lib/site-packages/django/contrib/gis/admin/widgets.py) they ignore the value if it's not of the same expected type (or if it's not GEOMETRY):

    value ignored because it's not GEOMETRY

    So I've commented those 3 lines and now it works.

    The working solution I've implemented is:

    if (value and value.geom_type.upper() != self.geom_type and
            self.geom_type != 'GEOMETRY' and
            (self.geom_type == 'MULTIPOLYGON' and
             'POLYGON' not in value.geom_type.upper())):
        value = None