What is the right way to insert a Point to a PostGIS database using Python?
2 Answers 2
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 thatpsycopg2
can handle the substitution.
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.
-
Excellent, thank you! I wonder if there is a performance difference between these two approaches.Adam Matan– Adam Matan2014年08月05日 06:43:06 +00:00Commented 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.Mike T– Mike T2014年08月05日 23:45:00 +00:00Commented Aug 5, 2014 at 23:45