Using SQLAlchemy with Spatial Databases
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Administrative functions and tools for managing spatial databases, including automatic DDL event handling, spatial index creation, and database-specific initialization procedures.
Automatic management of spatial database schema events with support for spatial indexes and metadata.
def setup_ddl_event_listeners():
"""
Setup DDL event listeners to automatically process spatial columns.
Automatically called when importing geoalchemy2. Registers event handlers for:
- before_create: Handle spatial indexes before table creation
- after_create: Restore column lists and create spatial metadata
- before_drop: Remove spatial metadata before table drop
- after_drop: Clean up spatial references after table drop
- column_reflect: Handle spatial column reflection during introspection
- after_parent_attach: Automatically add spatial indexes to columns
"""The DDL event system automatically handles:
Spatial database engine initialization and configuration management.
class GeoEngine:
"""
SQLAlchemy plugin for spatial database engine initialization.
Automatically registered as a SQLAlchemy plugin via entry points.
Provides database-specific spatial initialization when engines are created.
"""Usage examples:
from sqlalchemy import create_engine
from geoalchemy2.admin.plugin import GeoEngine
# Engine automatically configured for spatial operations
engine = create_engine(
'postgresql://user:pass@localhost/spatial_db',
plugins=[GeoEngine()] # Explicitly add if needed
)
# Or use standard engine creation (plugin auto-registered)
engine = create_engine('postgresql://user:pass@localhost/spatial_db')Initialize SpatiaLite extension for SQLite databases with spatial capabilities.
def load_spatialite(dbapi_conn, *args):
"""
Load SpatiaLite extension for SQLite database connections.
Parameters:
- dbapi_conn: SQLite database connection
- *args: Additional arguments (unused)
Automatically loads the SpatiaLite extension library and initializes
spatial metadata tables. Use as a SQLAlchemy engine event listener.
"""Usage examples:
from sqlalchemy import create_engine, event
from geoalchemy2.admin.dialects.sqlite import load_spatialite
# Method 1: Using engine events
engine = create_engine('sqlite:///spatial.db')
event.listen(engine, 'connect', load_spatialite)
# Method 2: Direct import triggers automatic setup
from geoalchemy2 import load_spatialite
engine = create_engine('sqlite:///spatial.db')
# load_spatialite automatically registered as connect event
# Create tables with spatial columns
Base.metadata.create_all(engine)Initialize GeoPackage databases with OGC standard compliance and spatial capabilities.
def load_spatialite_gpkg(dbapi_conn, *args, **kwargs):
"""
Load SpatiaLite extension for GeoPackage database connections.
Parameters:
- dbapi_conn: SQLite database connection for GeoPackage
- *args: Additional arguments
- **kwargs: Keyword arguments including connection parameters
Initializes GeoPackage-specific spatial capabilities including:
- OGC GeoPackage standard compliance
- Spatial reference system metadata
- Built-in R-tree spatial indexing
"""Usage examples:
from sqlalchemy import create_engine, event
from geoalchemy2.admin.dialects.geopackage import load_spatialite_gpkg
# Initialize GeoPackage database
engine = create_engine('sqlite+pysqlite:///data.gpkg')
event.listen(engine, 'connect', load_spatialite_gpkg)
# Create spatial tables following GeoPackage standard
Base.metadata.create_all(engine)Select appropriate database dialect implementations for spatial operations.
def select_dialect(dialect_name: str):
"""
Select database dialect implementation for spatial operations.
Parameters:
- dialect_name: str, database dialect name
("postgresql", "mysql", "mariadb", "sqlite", "geopackage")
Returns:
Dialect-specific implementation module with functions:
- before_create, after_create, before_drop, after_drop
- reflect_geometry_column
- bind_processor_process
"""Supported dialects:
Automatic and manual spatial index creation and management.
# Automatic index creation via column attachment events
def after_parent_attach(column, table):
"""
Automatically add spatial indexes when spatial columns are attached to tables.
Creates appropriate spatial indexes based on:
- Column type (Geometry, Geography, Raster)
- Database dialect capabilities
- Index configuration options (N-D indexes, etc.)
"""Manual index management:
from sqlalchemy import Index
from geoalchemy2.admin.dialects.common import _spatial_idx_name
# Create spatial index manually
spatial_index = Index(
_spatial_idx_name('table_name', 'geom_column'),
MyTable.geom,
postgresql_using='gist'
)
# For N-D indexes (PostgreSQL)
nd_index = Index(
_spatial_idx_name('table_name', 'geom_column') + '_nd',
MyTable.geom,
postgresql_using='gist',
postgresql_ops={'geom': 'gist_geometry_ops_nd'}
)# PostGIS-specific initialization
from geoalchemy2.admin.dialects import postgresql
# Automatic handling of:
# - PostGIS extension loading
# - spatial_ref_sys table management
# - geometry_columns metadata
# - Advanced indexing options (GiST, SP-GiST, BRIN)# MySQL spatial administration
from geoalchemy2.admin.dialects import mysql, mariadb
# Handles:
# - Geometry type validation
# - SRID constraint enforcement
# - Spatial index creation with R-tree
# - NOT NULL constraints for indexed columns# SpatiaLite administration
from geoalchemy2.admin.dialects import sqlite
# Manages:
# - SpatiaLite extension loading
# - Spatial metadata initialization
# - Virtual spatial index tables
# - Geometry column registration# GeoPackage administration
from geoalchemy2.admin.dialects import geopackage
# Provides:
# - OGC GeoPackage standard compliance
# - Built-in spatial reference systems
# - R-tree spatial indexing
# - Geometry type enforcementComplete setup workflow for new spatial databases:
from sqlalchemy import create_engine, MetaData
from geoalchemy2 import Geometry, load_spatialite
from geoalchemy2.admin import setup_ddl_event_listeners
# 1. Create engine with appropriate dialect
engine = create_engine('postgresql://user:pass@localhost/new_spatial_db')
# or for SQLite
engine = create_engine('sqlite:///new_spatial.db')
# 2. DDL events automatically set up via import
# setup_ddl_event_listeners() called automatically
# 3. Define spatial models
class SpatialTable(Base):
__tablename__ = 'spatial_features'
id = Column(Integer, primary_key=True)
name = Column(String)
geom = Column(Geometry('POLYGON', srid=4326)) # Index auto-created
# 4. Create all tables and indexes
Base.metadata.create_all(engine)Support for evolving spatial schemas:
# Spatial columns automatically handled during reflection
from sqlalchemy import MetaData
metadata = MetaData(bind=engine)
metadata.reflect()
# Spatial columns properly reflected with types and indexes
spatial_table = metadata.tables['spatial_features']
geom_column = spatial_table.c.geom # Properly typed as Geometry
# Existing spatial indexes automatically discovered
spatial_indexes = [idx for idx in spatial_table.indexes
if 'gist' in str(idx) or 'spatial' in idx.name]Ensure spatial operations work across different database backends:
from geoalchemy2.admin import select_dialect
# Automatically handles dialect differences
def create_spatial_table(engine):
dialect = select_dialect(engine.dialect.name)
# Dialect-specific setup handled automatically
Base.metadata.create_all(engine)
# Spatial indexes created appropriately for each database
return True
# Works with any supported database
postgres_engine = create_engine('postgresql://...')
sqlite_engine = create_engine('sqlite://...')
mysql_engine = create_engine('mysql://...')
for engine in [postgres_engine, sqlite_engine, mysql_engine]:
create_spatial_table(engine) # Automatically handles differencesAdministrative functions provide comprehensive error handling:
from geoalchemy2.exc import ArgumentError
try:
# Spatial column with conflicting options
column = Column(Geometry(use_N_D_index=True, spatial_index=False))
except ArgumentError as e:
# "spatial_index must be True when use_N_D_index is True"
print(f"Configuration error: {e}")
# Diagnostic information available
from geoalchemy2.admin.dialects.common import _check_spatial_type
spatial_column = MyTable.geom
is_geometry = _check_spatial_type(spatial_column.type, Geometry)
is_raster = _check_spatial_type(spatial_column.type, Raster)Administrative functions optimize spatial database performance:
Install with Tessl CLI
npx tessl i tessl/pypi-geoalchemy2