Cassandra Python Driver

The DataStax Python Driver is the official library for connecting Python applications to Apache Cassandra. It provides a Cluster object that manages connections, a Session object for executing queries, and support for prepared statements, asynchronous execution, and result set mapping to Python objects.

Installation

pip install cassandra-driver

For better performance, install the optional C extensions:

pip install cassandra-driver[speedups]

Connecting to Cassandra

from cassandra.cluster import Cluster
from cassandra.auth import PlainTextAuthProvider

auth = PlainTextAuthProvider(username='alice', password='Al1ce$ecure!')

cluster = Cluster(
  contact_points=['127.0.0.1'],
  port=9042,
  auth_provider=auth
)

session = cluster.connect('ecommerce')
print("Connected to keyspace:", session.keyspace)

Multi-Node Connection

cluster = Cluster(
  contact_points=['10.0.0.1', '10.0.0.2', '10.0.0.3'],
  port=9042,
  auth_provider=auth
)
session = cluster.connect('ecommerce')

Executing Simple Queries

rows = session.execute("SELECT product_id, name, price FROM products LIMIT 10")

for row in rows:
  print(f"Product: {row.product_id} | {row.name} | ${row.price:.2f}")

Prepared Statements (Best Practice)

Prepare all frequently-used CQL statements at startup. The driver sends the statement text once, and all subsequent executions only send bound parameter values — faster and safer.

# Prepare at startup:
insert_product = session.prepare("""
  INSERT INTO products (product_id, name, price, category)
  VALUES (?, ?, ?, ?)
""")

select_by_cat = session.prepare("""
  SELECT product_id, name, price
  FROM products_by_category
  WHERE category = ?
  ORDER BY price ASC
  LIMIT 20
""")

# Execute with bound values:
from uuid import uuid4
from decimal import Decimal

session.execute(insert_product, (uuid4(), 'Bluetooth Speaker', Decimal('49.99'), 'Electronics'))

rows = session.execute(select_by_cat, ('Electronics',))
for row in rows:
  print(row.name, row.price)

Consistency Level per Query

from cassandra import ConsistencyLevel
from cassandra.query import SimpleStatement

stmt = SimpleStatement(
  "SELECT * FROM orders_by_customer WHERE customer_id = %s",
  consistency_level=ConsistencyLevel.LOCAL_QUORUM
)

rows = session.execute(stmt, (customer_id,))

Asynchronous Queries

# Fire and forget (async):
future = session.execute_async(insert_product,
  (uuid4(), 'HDMI Cable', Decimal('14.99'), 'Electronics'))

# Do other work while query executes...

# Wait for result when needed:
try:
  result = future.result()
  print("Insert successful")
except Exception as e:
  print(f"Insert failed: {e}")

Async Batch Ingestion

from concurrent.futures import as_completed

products = [
  (uuid4(), 'USB Hub',      Decimal('29.99'), 'Electronics'),
  (uuid4(), 'Mouse Pad',    Decimal(' 9.99'), 'Accessories'),
  (uuid4(), 'Laptop Stand', Decimal('39.99'), 'Accessories'),
]

futures = [session.execute_async(insert_product, p) for p in products]

for future in futures:
  try:
    future.result()
  except Exception as e:
    print(f"Error: {e}")

Handling Large Result Sets with Paging

from cassandra.query import SimpleStatement

stmt = SimpleStatement(
  "SELECT * FROM products_by_category WHERE category = 'Electronics'",
  fetch_size=50   # 50 rows per page
)

# Driver fetches pages automatically as you iterate:
for row in session.execute(stmt):
  print(row.name, row.price)

Named Tuple and Dict Results

# Default: returns named tuples (access by column name)
row = session.execute("SELECT name, price FROM products WHERE product_id = %s",
                      (product_id,)).one()
print(row.name)   # named tuple access
print(row.price)

# Convert to dictionary:
row_dict = row._asdict()
print(row_dict['name'])

Object Mapping with cqlengine

The driver includes cqlengine, an ORM-style mapper that lets you define Cassandra tables as Python classes.

from cassandra.cqlengine import columns
from cassandra.cqlengine.models import Model
from cassandra.cqlengine.management import sync_table
from cassandra.cqlengine import connection

connection.setup(['127.0.0.1'], 'ecommerce', protocol_version=4)

class Product(Model):
  __keyspace__ = 'ecommerce'
  product_id = columns.UUID(primary_key=True, default=uuid4)
  name       = columns.Text()
  price      = columns.Decimal()
  category   = columns.Text()

# Create table if not exists:
sync_table(Product)

# Insert:
Product.create(name='Mechanical Keyboard', price=Decimal('89.99'), category='Electronics')

# Query:
products = Product.objects.filter(product_id=some_uuid)
for p in products:
  print(p.name, p.price)

Batch Statements

from cassandra.query import BatchStatement, BatchType

batch = BatchStatement(batch_type=BatchType.LOGGED)
batch.add(insert_product, (uuid4(), 'Webcam', Decimal('59.99'), 'Electronics'))
batch.add(insert_product, (uuid4(), 'Ring Light', Decimal('34.99'), 'Accessories'))
session.execute(batch)

Closing Connections Properly

session.shutdown()
cluster.shutdown()

Use a context manager or try/finally block in long-running scripts to ensure clean shutdown.

Error Handling

from cassandra import WriteTimeout, ReadTimeout, Unavailable

try:
  session.execute(insert_product, (uuid4(), 'Tablet', Decimal('299.99'), 'Electronics'))
except WriteTimeout as e:
  print(f"Write timed out: {e}")
  # Write may have partially succeeded — check before retrying
except Unavailable as e:
  print(f"Not enough replicas: {e}")
except Exception as e:
  print(f"Unexpected error: {e}")

Connection Configuration Reference

Parameter              Purpose                          Default
──────────────────────────────────────────────────────────────────
contact_points         Initial nodes to contact         ['127.0.0.1']
port                   CQL native transport port        9042
auth_provider          Authentication credentials       None
load_balancing_policy  How to pick replica nodes        DC-aware round robin
default_consistency    Default consistency level        LOCAL_ONE
connect_timeout        Connection establishment timeout 5 seconds
request_timeout        Individual query timeout         10 seconds

Summary

The DataStax Python Driver connects Python applications to Cassandra with minimal setup. Use the Cluster class to manage connections and the Session class to execute queries. Always use prepared statements for repeated queries to save parsing overhead. Use execute_async for concurrent writes, automatic paging for large result sets, and cqlengine for ORM-style data access. Handle WriteTimeout carefully — it does not always mean the write failed, since some replicas may have accepted it.

Leave a Comment

Your email address will not be published. Required fields are marked *