在 FastAPI 中与 PostGIS(PostgreSQL 的地理空间扩展)数据库交互时,我们可以使用 psycopg2
(PostgreSQL 的 Python 连接库)和 SQLAlchemy
来进行操作。如果需要进行地理空间查询或存储地理空间数据,GeoAlchemy2
是一个常用的库,它扩展了 SQLAlchemy,使其能够处理地理空间数据。下面是如何在 FastAPI 中与 PostGIS 数据库集成的详细步骤。
首先,安装必要的依赖库,包括 FastAPI、SQLAlchemy、GeoAlchemy2 和 psycopg2。
pip install fastapi uvicorn sqlalchemy geoalchemy2 psycopg2
psycopg2
用于连接 PostgreSQL 数据库。geoalchemy2
用于在 SQLAlchemy 中支持地理空间数据类型(如 POINT
、POLYGON
等)。SQLAlchemy
用于 ORM 操作。在这个示例中,我们将使用 SQLAlchemy 来连接 PostGIS 数据库,并通过 GeoAlchemy2
来操作地理空间数据。
首先,创建一个连接到 PostGIS 数据库的 SQLAlchemy 引擎,并定义一个数据模型来存储地理空间数据。
from fastapi import FastAPI, Depends
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from geoalchemy2 import Geometry
from sqlalchemy.future import select
# 配置数据库连接 URL(PostGIS 数据库)
DATABASE_URL = "postgresql://user:password@localhost/dbname"
# 创建 SQLAlchemy 引擎
engine = create_engine(DATABASE_URL, echo=True)
# 创建数据库会话
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# 创建模型基础类
Base = declarative_base()
# 定义数据模型
class Location(Base):
__tablename__ = "locations"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, index=True)
location = Column(Geometry(geometry_type='POINT', srid=4326))
# 创建数据库表
Base.metadata.create_all(bind=engine)
在这个模型中,我们定义了一个名为 Location
的表,该表包含:
id
: 主键。name
: 名称字段,用于存储位置名称。location
: 地理空间字段,使用 GeoAlchemy2
的 Geometry
类型,这里指定为 POINT
类型,表示经纬度。接下来,我们将创建一些路由来插入和查询地理空间数据。
from fastapi import FastAPI, HTTPException
from sqlalchemy.orm import Session
from pydantic import BaseModel
from geoalchemy2.shape import to_shape
from shapely.geometry import Point
app = FastAPI()
# Pydantic 模型,用于验证请求体数据
class LocationCreate(BaseModel):
name: str
latitude: float
longitude: float
@app.post("/locations/")
def create_location(location: LocationCreate, db: Session = Depends(get_db)):
# 创建一个 Point 对象(经纬度)
point = Point(location.longitude, location.latitude)
# 将 Point 转换为 PostGIS 所需的格式
geo_point = to_shape(point)
# 插入数据到数据库
db_location = Location(name=location.name, location=geo_point)
db.add(db_location)
db.commit()
db.refresh(db_location)
return db_location
LocationCreate
是一个 Pydantic 模型,用于接收请求体中的数据。Point
对象,表示地理位置。GeoAlchemy2
的 to_shape
函数将 Point
转换为数据库可以存储的格式。from sqlalchemy.orm import Session
from sqlalchemy import func
from shapely.geometry import Point
from geoalchemy2.functions import ST_Distance
@app.get("/locations/nearby/")
def get_nearby_locations(latitude: float, longitude: float, radius: float, db: Session = Depends(get_db)):
# 创建查询点
point = Point(longitude, latitude)
# 使用 PostGIS 的地理空间函数查询附近的地点
query = db.query(Location).filter(
ST_Distance(Location.location, point) < radius # 半径范围内查询
)
locations = query.all()
return locations
ST_Distance
是一个 PostGIS 提供的函数,用于计算地理空间数据之间的距离。get_nearby_locations
路由根据经纬度和半径查询附近的地点。# 获取数据库会话
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
运行 FastAPI 应用:
uvicorn app:app --reload
使用以下 POST 请求将一个新位置插入数据库:
POST /locations/
请求体:
{
"name": "Eiffel Tower",
"latitude": 48.8584,
"longitude": 2.2945
}
例如,查询距离某个点 1000 米以内的所有位置:
GET /locations/nearby/?latitude=48.8584&longitude=2.2945&radius=1000
在 FastAPI 中,我们通过 SQLAlchemy 和 GeoAlchemy2 实现了 PostGIS 数据库的基本操作。你可以利用 PostGIS 提供的丰富地理空间查询和操作功能,例如:
ST_Within
: 判断一个地理对象是否在另一个对象内。ST_Intersects
: 判断两个地理对象是否相交。ST_Contains
: 判断一个地理对象是否包含另一个对象。ST_Area
: 计算多边形的面积。ST_Length
: 计算线的长度。这些查询都可以通过 SQLAlchemy 和 GeoAlchemy2 在 FastAPI 中轻松实现。
FastAPI 与 PostGIS 数据库的集成主要通过以下几个步骤完成:
psycopg2
连接到 PostGIS 数据库。GeoAlchemy2
扩展 SQLAlchemy 以支持地理空间数据类型和查询。这种集成方式让 FastAPI 成为构建地理空间应用(如地图应用、位置服务等)的理想选择。