Subscribe to the Timescale Newsletter

By submitting you acknowledge Timescale's  Privacy Policy.

How to Use Psycopg2: The PostgreSQL Adapter for Python

How to Use Psycopg2: The PostgreSQL Adapter for Python

Python is one of the most popular programming languages, widely used for data analytics, visualizations, and data science. This guide will walk you through how to integrate PostgreSQL and your Python code via Psycopg2, one of the most popular PostgreSQL adapters.

Connecting to a PostgreSQL Database Using Python

PostgreSQL adapters serve as bridges that enable you to directly interact with your PostgreSQL database directly from your application and programming language.

In the particular case of Python, these are some of the most popular PostgreSQL adapters: 

pg8000

pg8000 stands out for its purity as a Python library and its seamless adherence to the Python Database API Specification v2.0. Unlike some adapters that rely on C extensions, pg8000 is written entirely in Python, which enhances its portability and ease of deployment across various environments.

It's particularly favored for applications that need to avoid the complexities of dealing with C extensions while maintaining efficient communication with PostgreSQL databases. The adapter strikes a balance between simplicity and functionality, making it an excellent choice for developers who prioritize straightforward implementation and usage.

pg8000 supports PostgreSQL 8.4 and up, as well as Python 2.6 to 2.7 and 3.2 to 3.7.

asyncpg

asyncpg is a distinct database adapter renowned for its superior performance and asynchronous processing capabilities. Designed explicitly for Python’s asyncio framework, asyncpg provides non-blocking, asynchronous communication with PostgreSQL databases. This ensures that applications remain responsive and scalable, particularly under heavy loads.

Its specialization in handling concurrent database connections effectively distinguishes asyncpg from other adapters, making it a go-to option for developers building high-performance, I/O-bound applications.

asyncpg supports PostgreSQL 9.2 and later versions, and it’s designed specifically for Python 3.5 and newer.

SQLAlchemy

SQLAlchemy is not only an adapter but more of a comprehensive SQL toolkit and Object-Relational Mapping (ORM) system for Python applications. It abstracts the complexities of database communication, allowing developers to interact with databases using Pythonic expressions.

SQLAlchemy's ORM enables developers to map Python objects to database tables, facilitating a higher-level, object-oriented perspective of database interaction. This feature-rich adapter is ideal for developers looking for an extensive set of tools to streamline both the basic and advanced aspects of database interaction.

SQLAlchemy can be used with a variety of databases, including PostgreSQL.

Psycopg2

Lastly, the focus of this blog post. Psycopg2 is a popular adapter for its comprehensive feature set, robustness, and scalability, firmly establishing itself as a favorite among Python developers interfacing with PostgreSQL. It is implemented with C extensions, which contributes to its performance efficiency.

Psycopg2 supports a range of PostgreSQL features, including server-side cursors, asynchronous notifications, and COPY commands. Furthermore, it is thread-safe and boasts connection pooling capabilities. Its widespread adoption is anchored on its reliability and compatibility with various versions of PostgreSQL and Python, making it a versatile choice for a diverse array of applications.

psycopg2 supports PostgreSQL 7.4 and up and Python versions from 2.5 to 3.7.

What Is the Difference Between Psycopg2 and SQLAlchemy? 

Psycopg2 and SQLAlchemy are very popular tools, so let’s spend a minute clarifying the difference between both. 

As we mentioned before, both tools are fundamentally different in character. SQLAlchemy is not only an adapter but an extensive SQL toolkit and ORM. With SQLAlchemy, developers can interact with databases using high-level Python expressions. It automatically translates these Python expressions into SQL code, reducing the need for writing SQL queries.

This abstraction makes SQLAlchemy particularly beneficial for developers who are either less experienced with SQL or are looking for a more Pythonic way to interact with databases.

In comparison, Psycopg2 offers a closer interaction with the PostgreSQL database, enabling developers to leverage PostgreSQL’s features to the fullest. It provides detailed control over database connections and query executions, making it a favorite for those who prioritize performance and direct database interaction.

In sum, here are the main differences between Psycopg2 and SQLAlchemy:

  • Psycopg2’s design is more straightforward, focusing on direct and efficient database interaction. SQLAlchemy, being an ORM, introduces an additional layer of abstraction, making database interactions more Pythonic and less complex.
  • Psycopg2 is rich in features that allow for a closer and more intricate interaction with PostgreSQL databases. SQLAlchemy offers a broader set of tools that simplify not only database connections but also query executions, mapping Python objects to database tables, and other advanced functionalities.
  • Psycopg2 provides developers with detailed control over SQL queries and database interactions. SQLAlchemy automates and abstracts many aspects of database communication, making it a suitable option for a less SQL-intensive experience.

Using Psycopg2: Top Advantages

Now, let’s get into Psycopg2!

This adapter seamlessly integrates Python and PostgreSQL, making it incredibly easy to work with these technologies in unison. It provides a set of Python modules that allow you to establish connections to PostgreSQL databases, execute SQL queries, and retrieve data easily. Psycopg2 adheres to Python’s database API specifications, ensuring a consistent and intuitive experience.

These are its main strengths: 

  • Connection management. Psycopg2 excels in establishing and maintaining robust connections between Python applications and PostgreSQL databases. It guarantees a reliable and uninterrupted data transfer channel, enhancing the efficiency of data exchange and communication.
  • Efficient SQL query execution. The adapter is equipped with capabilities for precise and rapid SQL query execution. It is adept at handling a variety of tasks, including data retrieval, record modifications, and executing complex operations, ensuring optimal performance and accuracy.
  • Real-time data synchronization. Psycopg2 helps you develop real-time applications, as it ensures that Python code is consistently synchronized with the PostgreSQL database. This feature facilitates the creation of responsive, data-driven applications that can effectively adapt to dynamic data changes.
  • Robusticity. Psycopg2 is recognized for its stability and reliability, making it the ideal choice for mission-critical applications. This library handles various PostgreSQL features, complex data types, and large objects, ensuring the precision and reliability needed for high-stakes projects.
  • Cross-compatibility. Psycopg2 seamlessly integrates with different Python versions and PostgreSQL versions, providing cross-compatibility and versatility for your projects. This ensures that your Python code remains functional across various environments.
  • Active community. Psycopg2 benefits from continuous development and a supportive community. This dedication to improvement ensures that Psycopg2 remains up-to-date with the latest advancements in Python and PostgreSQL, making it a reliable choice for your Python PostgreSQL interactions.
  • Enhanced security. Psycopg2 prioritizes data security by offering robust features, including support for SSL connections. This added layer of security helps safeguard your sensitive data, maintaining data integrity and confidentiality in your transactions.

When to Use Psycopg2: Example Use Cases of Using Python and PostgreSQL 

Data analytics and reporting 

Data analysts and scientists frequently employ Psycopg2 for seamless access to PostgreSQL databases. For instance, imagine a data analyst at a marketing firm who uses Psycopg2 to retrieve customer data from a PostgreSQL database. With this data, they can create insightful reports, analyze trends, and make data-driven decisions to enhance marketing strategies.

Web development 

In web development, Psycopg2 is invaluable for building dynamic, database-driven websites. Consider an e-commerce website where Psycopg2 is used to manage product inventory, customer orders, and user accounts stored in a PostgreSQL database. This ensures a smooth shopping experience for customers and efficient inventory management for the business.

Business applications

Businesses across various industries leverage Psycopg2 for mission-critical applications. For example, a financial institution may employ Psycopg2 to maintain a secure and robust database of customer transactions and accounts. This ensures data integrity, reliability, and swift access to financial data.

IoT and real-time applications 

In the realm of IoT, Psycopg2 plays a crucial role in capturing and storing real-time sensor data. Imagine a smart city project that relies on Psycopg2 to collect and analyze data from various sensors, such as traffic cameras and air quality monitors. This data can be used to optimize traffic flow, improve air quality, and enhance overall city management.

Scientific research

Scientists and researchers utilize Psycopg2 for storing and analyzing scientific data. For instance, in a research project involving climate data, Psycopg2 could be used to store temperature and weather data in a Psycopg2 database. Researchers can then perform complex data analysis and generate climate models to better understand climate patterns.

Installing Psycopg2: Instructions  

Before we begin, ensure that you have the following prerequisites in place:

Installation steps

Psycopg2 can be easily installed using pip, Python's package manager. Open your terminal or command prompt and run the following command:

pip install psycopg2

You can also install the latest version of Psycopg2, including the necessary binary dependencies using this command:

pip install psycopg2-binary

đź“š Editor's note: If you're using Timescale, you can also find guidelines on how to install Psycopg2 in our documentation.


To ensure that Psycopg2 is correctly installed, perform the following checks:

  • Open a Python interpreter or create a Python script and import Psycopg2. If there are no import errors, Psycopg2 is installed correctly.
  • You can verify the installed Psycopg2 version with the following code:
print(psycopg2.__version__)

Troubleshooting common installation issues

While Psycopg2 installation is generally straightforward, if you encounter some issues, run through this checklist:

  • Psycopg2 relies on PostgreSQL’s C library. If you encounter missing library errors during installation, ensure you have the PostgreSQL development headers and libraries installed on your system.
  • If you are using a virtual environment for your Python development, make sure it is activated when you run the installation command.
  • Verify that your Python version meets Psycopg2's requirements. If you encounter compatibility issues, consider upgrading to a compatible Python version.

Connecting to Your PostgreSQL Database Using Psycopg2

Now that you have everything installed, let's connect to your PostgreSQL database!

Here’s an example of establishing a database connection using Psycopg2:

import psycopg2
# Defining database connection parameters
db_params = {
    "host": "your_database_host",
    "database": "your_database_name",
    "user": "your_database_user",
    "password": "your_database_password",
    "port": "your_database_port"
}
try:
    # Establishing a connection to the database
    connection = psycopg2.connect(**db_params)
    # Creating a cursor object to interact with the database
    cursor = connection.cursor()
    # Performing database operations here...
except (Exception, psycopg2.Error) as error:
    print(f"Error connecting to the database: {error}")

finally:
    if connection:
        cursor.close()
        connection.close()
        print("Database connection closed.")

In this code, we first import the psycopg2 module, which provides the functionality needed to interact with PostgreSQL databases from Python. The db_params dictionary contains the following parameters necessary to establish a database connection:

  • host: specifies the hostname or IP address of the database server.
  • database: specifies the name of the database you want to connect to.
  • user: specifies the username for authentication.
  • password: specifies the password for authentication.
  • port: specifies the port number to connect to. The default is 5432 for PostgreSQL.

The code is wrapped in a try block, which is used to handle exceptions or errors that may occur during the database connection process. Inside the try block, psycopg2.connect(**db_params) is used to establish a connection to the database. The **db_params syntax passes the connection parameters defined in the dictionary to the connect function.

After successfully establishing a connection, a cursor object is created using connection.cursor(). The cursor is used to execute SQL queries and interact with the database. The except block catches any exceptions or errors that may occur during the connection process, and it prints an error message if there is an issue. The finally block ensures that the cursor and connection are properly closed.

Running PostgreSQL Queries Using Psycopg2

In this section, we assume that the database connection has already been established, so we’ll focus on showing some query examples you can run using Psycopg2.

Executing SELECT queries using Psycopg2

The below code shows how to execute a SELECT query with Psycopg2:

# Defining the SELECT query
select_query = "SELECT column1, column2 FROM your_table_name WHERE condition;"

# Executing the SELECT query
cursor.execute(select_query)

# Fetching and printing the results
result = cursor.fetchall()
for row in result:
    print(row)

With this code, we achieve the following:

  • We define the SELECT query and include the desired columns and a condition.
  • The execute method is used to execute the query.
  • The results are fetched using cursor.fetchall() , and we loop through the rows to print them.

Executing INSERT queries using psycopg2

INSERT queries are executed similarly:

# Defining the INSERT query
insert_query = "INSERT INTO your_table_name (column1, column2) VALUES (value1, value2);"

# Executing the INSERT query
cursor.execute(insert_query)

# Committing the transaction to save changes
connection.commit()

Executing UPDATE and DELETE queries using Psycopg2

Same with UPDATES and DELETES:

# Defining the UPDATE query
update_query = "UPDATE your_table_name SET column1 = new_value WHERE condition;"

# Executing the UPDATE query
cursor.execute(update_query)

# Committing the transaction to save changes
connection.commit()
# Defining the DELETE query
delete_query = "DELETE FROM your_table_name WHERE condition;"

# Executing the DELETE query
cursor.execute(delete_query)

# Committing the transaction to save changes
connection.commit()

Troubleshooting: Fixing Common Psycopg2 Errors 

Now that you have everything up and running, let’s explore the most frequently encountered errors you might see when working with Psycopg2 to interact with PostgreSQL databases, guiding you on how to remedy them.

psycopg2.OperationalError

import psycopg2

try:
    connection = psycopg2.connect(
        dbname="yourdbname",
        user="youruser",
        password="yourpassword",
        host="yourhost",
        port="yourport"
    )
    # Additional database operations here

except psycopg2.OperationalError as error:
    print(f"OperationalError: {error}")


The psycopg2.OperationalError is one of the common errors that you might see. It generally encapsulates one of these issues: 

  • Connection failure. The problem might be related to establishing a connection to the PostgreSQL server. Ensure that the server is up and running and accessible from the client machine.
  • Invalid database name or credentials. Mistyping or incorrect credentials also can lead to an OperationalError. Make sure that the database name, username, and password are correct. 
  • Networking issues. Networking issues, such as incorrect host, port, or network unreachable, can also trigger this error. Make sure that the networking configurations are correct and that the server is reachable.
  • Insufficient privileges. The user might not have the required privileges to connect to the specified database. Ensure the user has the necessary permissions.
  • Server overload or downtime. The PostgreSQL server might be down or experiencing overload issues—confirm that the server is in good health and operational.

In order to fix the error, you can go through these steps. You’ll typically resolve the issue: 

  • Ensure that the PostgreSQL server is running and listening on the correct port.
  •  Confirm that the connection parameters (including host, port, user, password, and database name) are correct. 
  • Ensure the network connection between the client and server is stable and that firewalls or network ACLs are not blocking the connection.
  •  Confirm that the user has the required permissions to connect to the database.
  • Examine the PostgreSQL and system logs for additional details on the error.


psycopg2.ProgrammingError

import psycopg2

try:
    connection = psycopg2.connect(
        dbname="yourdbname",
        user="youruser",
        password="yourpassword",
        host="yourhost",
        port="yourport"
    )
    cursor = connection.cursor()
    # Replace the next line with your actual SQL query
    cursor.execute("YOUR SQL QUERY HERE")
    connection.commit()

except psycopg2.ProgrammingError as error:
    print(f"ProgrammingError: {error}")

This error is usually a signal of an anomaly within the structure or syntax of the SQL query being executed. These are the most common reasons: 

  • SQL syntax errors. You might have a typos, misplaced operator, or other mistake in your SQL syntax.
  • Invalid table/column names. You might be referencing non-existent tables or columns.
  • Incorrect data types. This error also shows up if you have mismatched data types or if you’re attempting to insert an incorrect data type into a column.
  • Privilege issues. Lastly, you might be trying to access or manipulate the database objects without the necessary privileges.

To troubleshoot this error, run through this checklist: 

  • Review the SQL query for any syntax errors. Utilize SQL linters or built-in database functions to check the syntax. 
  • Ensure that all referenced table and column names exist and are spelled correctly.
  • Ensure that you are inserting data that matches the expected data types of the columns.
  • Verify if the database user has adequate privileges to execute the intended operations on the database, tables, or columns.

Also, pay close attention to the error message—it often contains information on what’s wrong with the SQL query.

psycopg2.IntegrityError

import psycopg2

try:
    connection = psycopg2.connect(
        dbname="yourdbname",
        user="youruser",
        password="yourpassword",
        host="yourhost",
        port="yourport"
    )
    cursor = connection.cursor()
    # Replace the next line with your actual SQL query
    cursor.execute("YOUR SQL QUERY HERE")
    connection.commit()

except psycopg2.IntegrityError as error:
    print(f"IntegrityError: {error}")
    connection.rollback()


This error occurs when an attempted operation threatens database integrity constraints, for example:

  • Unique constraints violation (i.e., attempting to insert a duplicate value in a column that is constrained to have only unique values). 
  • Foreign key constraints violation (i.e., trying to insert a value in a foreign key column that does not exist in the referenced primary key column).
  • Check constraints violation (i.e., inserting data that does not satisfy the check constraints of the columns). 
  • Not null constraints violation (i.e., attempting to insert a null value into a column that is defined as NOT NULL). 

Here's how you can troubleshoot:

  • Review the error message, as it usually contains specific information about the nature of the integrity violation. 
  • Ensure that the data being inserted adheres to the integrity constraints defined for the table.
  • Review the integrity constraints on the table to understand the rules and ensure compliance.

psycopg2.DataError

import psycopg2

try:
    connection = psycopg2.connect(
        dbname="yourdbname",
        user="youruser",
        password="yourpassword",
        host="yourhost",
        port="yourport"
    )
    cursor = connection.cursor()
    # Replace the next line with your actual SQL query
    cursor.execute("YOUR SQL QUERY HERE")
    connection.commit()

except psycopg2.DataError as error:
    print(f"DataError: {error}")
    connection.rollback()

This error is related to data values, specifically when the type or format of the data being inserted or manipulated is not compatible with the expected data type of the database column. To fix it, examine the data being inserted or updated to ensure its type, format, and value are compatible with the column’s specifications. 

Psycopg2 Best Practices 

In addition to the troubleshooting tips we shared in the previous section, some general best practices will help you run Psycopg2 with fewer errors (and fix them quicker when they arise).

Logging errors   

By implementing a logging mechanism in your Psycopg2 workflow, it’ll be easier to track and analyze complex issues. This is a great practice for applications that interact with databases. 

For example, consider the following code:

import psycopg2
import logging

# Configuring logging
logging.basicConfig(filename='database_errors.log', level=logging.ERROR, 
                    format='%(asctime)s:%(levelname)s:%(message)s')

try:
    connection = psycopg2.connect(
        dbname="yourdbname",
        user="youruser",
        password="yourpassword",
        host="yourhost",
        port="yourport"
    )
    cursor = connection.cursor()
    cursor.execute("YOUR SQL QUERY HERE")
    connection.commit()

except (Exception, psycopg2.Error) as error:
    # Rolling back the transaction in case of error
    connection.rollback()
    # Logging the error
    logging.error(f"Error: {error}")
    print(f"Error: {error}")

finally:
    # Closing the cursor and connection
    if connection:
        cursor.close()
        connection.close()


This logging configuration is enriched with a format parameter to include a timestamp, severity level, and the error message. This allows you to record your errors more comprehensively, ensuring that transactions are rolled back in the event of an error and avoiding partial data commits that can lead to inconsistencies.

It's also essential to close database resources like cursors and connections to prevent resource leakage, and this can be effectively handled within a final block. 

Always check your database connection

Verify that the database connection is still open before executing queries to avoid errors related to a closed connection:

import psycopg2

# Assuming 'connection' is the established database connection

try:
    # Checking if the connection is still open
    if connection.closed == 0:
        # Database operations here
    else:
        print("Database connection is closed.")
except (Exception, psycopg2.Error) as error:
    print(f"Error: {error}")


Sanitize your input to prevent SQL injection attacks 

A SQL injection attack is a type of security vulnerability that occurs when an attacker is able to insert malicious SQL code into a query. This can happen when an application allows user input to be included in SQL queries without proper validation or escaping.

When the database executes this malicious input, it can lead to unauthorized access, data theft, corruption, or other adverse impacts. This is something you want to protect yourself from when working with Psycopg2. 

In this snippet, user-provided input is sanitized and validated to prevent SQL injection attacks. The safe_input variable is created using Psycopg2's adapt function, ensuring that user input is properly escaped and can be safely used in SQL queries:

import psycopg2

# User-provided input
user_input = "'; DROP TABLE users --"

try:
    # Sanitizing and validating user input
    safe_input = psycopg2.extensions.adapt(user_input).getquoted()
    
    # Using safe_input in our query
    query = f"SELECT * FROM users WHERE username = {safe_input};"

    # Executing the query
    cursor.execute(query)

except (Exception, psycopg2.Error) as error:
    print(f"Error: {error}")


Using Psycopg2 and TimescaleDB

In this section, we will cover a few examples of TimescaleDB operations that can be effectively managed through Psycopg2. TimescaleDB is a PostgreSQL extension that boosts PostgreSQL performance for data-intensive applications dealing with time-series data, such as IoT sensor data, energy metrics, tick financial data, and many more.

Creating hypertables using Psycopg2

Hypertables are the core feature of TimescaleDB. They automatically partition data by time, improving query and ingest performance and making data management more efficient. 

To transform your PostgreSQL tables into hypertables using Psycopg2, run:

import psycopg2

# Assuming a table 'your_table' with a time column 'time_column'
cursor.execute("SELECT create_hypertable('your_table', 'time_column');")


Querying TimescaleDB using Psycopg2

You can query TimescaleDB databases seamlessly using Psycopg2, just as you query PostgreSQL. You can leverage the library of SQL functions that TimescaleDB offers to write time-based queries more effectively—for example, using functions like time_bucket, which allows you to group entries into specified time intervals, simplifying the process of aggregating and analyzing data over time. 

For example, in this SQL query, the time_bucket function is used to create time intervals of one hour, facilitating the grouping and aggregation of temperature data within these intervals. The query then calculates the average temperature for each location within each time bucket, offering insights into temperature trends over time and across locations.

SELECT 
    time_bucket('1 hour', time) as one_hour_interval,
    location,
    AVG(temperature) as avg_temperature
FROM 
    conditions 
WHERE 
    temperature > 76 
GROUP BY 
    one_hour_interval, location 
ORDER BY 
    one_hour_interval DESC, avg_temperature DESC;


Conclusion 

In this comprehensive guide, we've delved into the world of Psycopg2 and how it can help you connect to your PostgreSQL database from your Python application.

If you could do a query performance boost in your PostgreSQL database, give Timescale a try. This PostgreSQL extension will make your queries faster via automatic partitioning, query planner enhancements, improved materialized views, columnar compression, and much more.

If you're running your PostgreSQL database on your own hardware, you can simply add the TimescaleDB extension. If you prefer to try Timescale in AWS, create a free account on our platform. It only takes a couple of seconds, no credit card required. 

Next steps

Also, don't forget to check out some of our Python resources, from time-series data analysis to OpenAI exploration:

Ingest and query in milliseconds, even at terabyte scale.
This post was written by
15 min read
PostgreSQL
Contributors

Related posts