14

What is the right way to insert a Point to a PostGIS database using Python?

underdark
84.9k22 gold badges237 silver badges418 bronze badges
asked Jul 27, 2014 at 8:47

2 Answers 2

25

First, install the psycopg2 package, a Pythonic interface for PostgreSQL.

Then, use ST_MakePoint:

>>> import psycopg2
>>> conn = psycopg2.connect(dbname=..., port=..., user=...,
 password=..., host=...)
>>> cur = conn.cursor()
>>> x, y, z, = 32, 34, 0
>>> cur.execute("SELECT ST_SetSRID(ST_MakePoint(%s, %s, %s),4326);", (x, y, z))
>>> cur.fetchall()
[('01010000A0E6100000000000000000404000000000000041400000000000000000',)]

ST_AsText can be used to validate the values:

>>> cur.execute("SELECT ST_AsText(ST_SetSRID(ST_MakePoint(%s, %s, %s),4326));", (x, y, z))
>>> cur.fetchall()
[('POINT Z (32 34 0)',)]

Notes

  • Remember that (lat, lon) is (y, x), not (x, y).
  • Always use parameters, rather than string manipulations, to prevent SQL injection. In this examples we tupled (x, y, z) at the end so that psycopg2 can handle the substitution.
answered Jul 27, 2014 at 8:47
23

For more complicated geometries, such as LineString and Polygon geometries, you can handle them with Shapely, then pass them through psycopg2 as hex-encoded WKB. Note that Shapely 1.3 or later is required to handle the export of 3D geometries with the wkb_hex property.

import psycopg2
from shapely.geometry import LineString
from shapely import wkb
conn = psycopg2.connect('...')
curs = conn.cursor()
# Make a Shapely geometry
ls = LineString([(2.2, 4.4, 10.2), (3.3, 5.5, 8.4)])
ls.wkt # LINESTRING Z (2.2 4.4 10.2, 3.3 5.5 8.4)
ls.wkb_hex # 0102000080020000009A999999999901409A999999999911406666666666662440666666...
# Send it to PostGIS
curs.execute('CREATE TEMP TABLE my_lines(geom geometry, name text)')
curs.execute(
 'INSERT INTO my_lines(geom, name)'
 'VALUES (ST_SetSRID(%(geom)s::geometry, %(srid)s), %(name)s)',
 {'geom': ls.wkb_hex, 'srid': 4326, 'name': 'First Line'})
conn.commit() # save data
# Fetch the data from PostGIS, reading hex-encoded WKB into a Shapely geometry
curs.execute('SELECT name, geom FROM my_lines')
for name, geom_wkb in curs:
 geom = wkb.loads(geom_wkb, hex=True)
 print('{0}: {1}'.format(name, geom.wkt))
# First Line: LINESTRING Z (2.2 4.4 10.2, 3.3 5.5 8.4)

Further note that similar can be accomplished by sending the geometry's WKT, however since it is converted to text, it is lossy and may reduce angstroms of precision. Transferring geometries as hex-encoded WKB is lossless, and preserves the exact precision of each coordinate.

answered Aug 5, 2014 at 6:15
2
  • Excellent, thank you! I wonder if there is a performance difference between these two approaches. Commented Aug 5, 2014 at 6:43
  • There is a 10% performance advantage building points with ST_MakePoint, which is great for point geometries. However, building more complex geometry types will generally be simpler with Shapely. Commented Aug 5, 2014 at 23:45

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.