The ODBC library you use when connecting Python to PostgreSQL is the psycopg2 Python library. This blog post will show use how to use it in Python and install it on your Fedora Linux installation.
You would import psycopg2 as follows in your Python code:
import psycopg2
Unfortunately, that only works on Linux servers when you’ve installed the library. That library isn’t installed with generic Python libraries. You get the following error when the psycopg2 library isn’t installed on your server.
Traceback (most recent call last):
File "python_new_hire.sql", line 1, in
import psycopg2
ModuleNotFoundError: No module named 'psycopg2'
You can install it on Fedora Linux with the following command:
yum install python3-psycopg2
It will install:
====================================================================================
Package Architecture Version Repository Size
====================================================================================
Installing:
python3-psycopg2 x86_64 2.7.7-1.fc30 fedora 160 k
Transaction Summary
====================================================================================
Install 1 Package
Total download size: 160 k
Installed size: 593 k
Is this ok [y/N]: y
Downloading Packages:
python3-psycopg2-2.7.7-1.fc30.x86_64.rpm 364 kB/s | 160 kB 00:00
------------------------------------------------------------------------------------
Total 167 kB/s | 160 kB 00:00
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
Preparing : 1/1
Installing : python3-psycopg2-2.7.7-1.fc30.x86_64 1/1
Running scriptlet: python3-psycopg2-2.7.7-1.fc30.x86_64 1/1
Verifying : python3-psycopg2-2.7.7-1.fc30.x86_64 1/1
Installed:
python3-psycopg2-2.7.7-1.fc30.x86_64
Complete!
Here’s a quick test case that you can run in PostgreSQL and Python to test all the pieces. The first SQL script creates a new_hire table and inserts two rows, and the Python program queries data from the new_hire table.
The new_hire.sql file creates the new_hire table and inserts two rows:
-- Environment settings for the script.
SET SESSION "videodb.table_name" = 'new_hire';
SET CLIENT_MIN_MESSAGES TO ERROR;
-- Verify table name.
SELECT current_setting('videodb.table_name');
-- ------------------------------------------------------------------
-- Conditionally drop table.
-- ------------------------------------------------------------------
DROP TABLE IF EXISTS new_hire CASCADE;
-- ------------------------------------------------------------------
-- Create table.
-- -------------------------------------------------------------------
CREATE TABLE new_hire
( new_hire_id SERIAL
, first_name VARCHAR(20) NOT NULL
, middle_name VARCHAR(20)
, last_name VARCHAR(20) NOT NULL
, hire_date TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
, PRIMARY KEY (new_hire_id));
-- Alter the sequence by restarting it at 1001.
ALTER SEQUENCE new_hire_new_hire_id_seq RESTART WITH 1001;
-- Display the table organization.
SELECT tc.table_catalog || '.' || tc.constraint_name AS constraint_name
, tc.table_catalog || '.' || tc.table_name AS table_name
, kcu.column_name
, ccu.table_catalog || '.' || ccu.table_name AS foreign_table_name
, ccu.column_name AS foreign_column_name
FROM information_schema.table_constraints AS tc JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
AND tc.table_schema = kcu.table_schema JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
AND ccu.table_schema = tc.table_schema
WHERE tc.constraint_type = 'FOREIGN KEY'
AND tc.table_name = current_setting('videodb.table_name')
ORDER BY 1;
SELECT c1.table_name
, c1.ordinal_position
, c1.column_name
, CASE
WHEN c1.is_nullable = 'NO' AND c2.column_name IS NOT NULL THEN 'PRIMARY KEY'
WHEN c1.is_nullable = 'NO' AND c2.column_name IS NULL THEN 'NOT NULL'
END AS is_nullable
, CASE
WHEN data_type = 'character varying' THEN
data_type||'('||character_maximum_length||')'
WHEN data_type = 'numeric' THEN
CASE
WHEN numeric_scale != 0 AND numeric_scale IS NOT NULL THEN
data_type||'('||numeric_precision||','||numeric_scale||')'
ELSE
data_type||'('||numeric_precision||')'
END
ELSE
data_type
END AS data_type
FROM information_schema.columns c1 LEFT JOIN
(SELECT trim(regexp_matches(column_default,current_setting('videodb.table_name'))::text,'{}')||'_id' column_name
FROM information_schema.columns) c2
ON c1.column_name = c2.column_name
WHERE c1.table_name = current_setting('videodb.table_name')
ORDER BY c1.ordinal_position;
-- Display primary key and unique constraints.
SELECT constraint_name
, lower(constraint_type) AS constraint_type
FROM information_schema.table_constraints
WHERE table_name = current_setting('videodb.table_name')
AND constraint_type IN ('PRIMARY KEY','UNIQUE');
-- Insert two test records.
INSERT INTO new_hire
( first_name, middle_name, last_name, hire_date )
VALUES
('Malcolm','Jacob','Lewis','2018-2-14')
,('Henry',null,'Chabot','1990-07-31');
You can put it into a local directory, connect as the student user to a videodb database, and run the following command (or any database you’ve created).
\i new_hire.sql
The new_hire.py file creates the new_hire table and inserts two rows:
# Import the PostgreSQL connector library.
import psycopg2
try:
# Open a connection to the database.
connection = psycopg2.connect( user="student"
, password="student"
, port="5432"
, dbname="videodb")
# Open a cursor.
cursor = connection.cursor()
# Assign a static query.
query = "SELECT new_hire_id, first_name, last_name " \
"FROM new_hire"
# Parse and execute the query.
cursor.execute(query)
# Fetch all rows from a table.
records = cursor.fetchall()
# Read through and print the rows as tuples.
for row in range(0, len(records)):
print(records[row])
except (Exception, psycopg2.Error) as error :
print("Error while fetching data from PostgreSQL", error)
finally:
# Close the database connection.
if (connection):
cursor.close()
connection.close()
You run it from the command line, like:
python3 ./new_hire.py
It should print:
(1001, 'Malcolm', 'Lewis')
(1002, 'Henry', 'Chabot')
As always, I hope this helps those trying to sort out how to connect Python to PostgreSQL.