1

I'm using GeoDjango and have a Django model with a PointField:

class ArchivrItem(models.Model):
    ...
    coordinate = models.PointField(srid=4326)

When I try to insert a new ArchivrItem, using latitude and longitude, I get this error:

ERROR:  new row for relation "archivr_archivritem" violates check constraint "enforce_srid_coordinate"

I can avoid Django and get the same error in postgresql directly by trying to do this:

INSERT INTO archivr_archivritem (coordinate) VALUES ('POINT(51.520667 -0.094833)');

I'm probably being naive and ignorant around SRID and point systems... what am I missing? Thanks.

UPDATE: I should add what the constraint is. The constraints on the table are:

"enforce_dims_coordinate" CHECK (st_ndims(coordinate) = 2)
"enforce_geotype_coordinate" CHECK (geometrytype(coordinate) = 'POINT'::text OR coordinate IS NULL)
"enforce_srid_coordinate" CHECK (st_srid(coordinate) = 4326)
Phil Gyford
  • 13,432
  • 14
  • 81
  • 143

2 Answers2

1

It sounds like you're trying to add a new ArchivrItem by doing this:

item = ArchivrItem(coordinate='POINT(51.520667 -0.094833)')
item.save()

And this is not getting the right default SRID for some reason I'm not sure about. However, specifying it explicitly should work, e.g.:

from django.contrib.gis.geos import Point
item = ArchivrItem(coordinate=Point(-0.094833, 51.520667, srid=4326))
item.save()

I'd say the srid is optional if it's going to match the model definition, but no harm in specifying it, and you can see if simply using the object way fixes it anyway. https://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#creating-and-saving-geographic-models has some more examples.

[Aside, note that POINT() is X then Y, i.e. lon then lat, not lat/lon. You can put a SRID in if it's extended WKT with "SRID=4326;POINT(-0.094833 51.520667)"]

  • Hmm, I've now tried all of these, with the same error: `item = ArchivrItem(coordinate=Point(5, 23))`, `item = ArchivrItem(coordinate=GEOSGeometry('SRID=4326;POINT(5 23)'))` and `item = ArchivrItem(coordinate=GEOSGeometry('POINT(5 23)', srid=4326))`. – Phil Gyford May 08 '12 at 16:11
  • I have successfully managed it directly in SQL though, by inserting this as a value: `ST_SetSrid(ST_PointFromText('POINT(5 23)'),4326)`. – Phil Gyford May 08 '12 at 16:12
  • PointFromText has a SRID argument, no need for SetSrid: http://www.postgis.org/docs/ST_PointFromText.html . Could you get it to output the SQL it's trying to run (that page has an example) and see what it's trying to do from Django? – Matthew Somerville May 08 '12 at 16:17
  • Ah, thanks. Hmm, so Django is logging this: `INSERT INTO "archivr_archivritem" ("coordinate") VALUES (ST_GeomFromEWKB('\x010100000000000000000014400000000000003740'::bytea)) RETURNING "archivr_archivritem"."id"; args=()` – Phil Gyford May 09 '12 at 09:47
  • Using Django 1.2.3, Postgres 8.4, all three versions you give work without error here, I'm afraid. My INSERTs from Django contain a EWKB that includes a SRID; yours above does not and is the equivalent of just 'POINT(5 23)'. I couldn't say where the srid is lost without greater access to the code. – Matthew Somerville May 09 '12 at 11:45
  • Oh well, thanks for trying Matthew! I'm on Django 1.4 and Postgres 9.1.2 and will have a deeper poke around inside when I get a moment. – Phil Gyford May 09 '12 at 14:41
0

After a colleague coming across the same issue, we appear to have tracked this down to an issue with the version of GEOS installed. Using a version with this problem, if p is a django.contrib.gis.geos.Point, p.wkb and p.ewkb return the same data - the EWKB lacks the SRID information. As Django uses EWKB to construct the SQL for import into PostGIS, this is why it fails, no matter the construction of the creation.

My previous comments were using Debian's 3.2.0 which does not show this issue at all. 3.2.3 is the version that is showing this issue here. Upgrading to 3.3.6 fixed the issue (and also tested 3.3.3 which is fine). I'll try other versions later today when I have more time to try and track it down further.

You can see your version of GEOS with:

from django.contrib.gis.geos.libgeos import geos_version
geos_version()
M Somerville
  • 4,499
  • 30
  • 38