You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI中如何在Pydantic v2正确声明Geoalchemy2 Geometry类型?

在FastAPI中为PostGIS的Geometry字段配置Pydantic v2 Schema

问题描述

使用FastAPI+PostGIS+Geoalchemy2+Alembic搭建项目,数据库表已通过Alembic创建完成,但无法在Pydantic v2的Schema中正确声明geom字段类型,需要该字段支持空间操作的类型转换与验证。

解决方案

Pydantic v2本身不原生支持Geoalchemy2的Geometry类型,需通过自定义Pydantic类型实现WKT字符串与Geoalchemy Geometry对象的双向转换,同时保证字段验证和序列化的正确性。

步骤1:创建自定义Pydantic类型

新建一个自定义类型文件(比如custom_types.py),实现对Geometry类型的验证和序列化逻辑:

from pydantic import GetCoreSchemaHandler
from pydantic_core import core_schema
from geoalchemy2 import WKTElement, Geometry
from typing import Any, Union

class GeometryType:
    @classmethod
    def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
        # 验证逻辑:将输入转换为Geoalchemy Geometry对象
        def validate(value: Union[str, Geometry]) -> Geometry:
            if isinstance(value, str):
                # 把WKT字符串转为带SRID的WKTElement(匹配数据库中的SRID=4326)
                return WKTElement(value, srid=4326)
            elif isinstance(value, Geometry):
                # 已经是Geometry对象,直接返回
                return value
            else:
                raise ValueError("geom字段必须是WKT格式字符串或Geoalchemy Geometry对象")

        # 序列化逻辑:将Geometry对象转为WKT字符串供前端接收
        def serialize(value: Geometry) -> str:
            return value.wkt if hasattr(value, 'wkt') else str(value)

        return core_schema.no_info_wrap_validator_function(
            validate,
            core_schema.union_schema([
                core_schema.str_schema(),
                core_schema.is_instance_schema(Geometry)
            ]),
            serialization=core_schema.plain_serializer_function_ser_schema(serialize)
        )

步骤2:在Schema中使用自定义类型

修改schemas.py,将geom字段的类型指定为自定义的GeometryType:

from typing import List
from pydantic import ConfigDict, BaseModel, Field
from .custom_types import GeometryType  # 导入自定义类型

class SolarParkBase(BaseModel):
    model_config = ConfigDict(from_attributes=True, arbitrary_types_allowed=True)

    name_of_model: str = Field("test-model")
    comment: str = "None"
    lat: List[float] = Field([599968.55, 599970.90, 599973.65, 599971.31, 599968.55])
    lon: List[float] = Field([5570202.63, 5570205.59, 5570203.42, 5570200.46, 5570202.63])
    geom: GeometryType = Field('POLYGON ((599968.55 5570202.63, 599970.90 5570205.59, 599973.65 5570203.42, 599971.31 5570200.46, 599968.55 5570202.63))')

关键说明

  • 输入验证:支持接收WKT格式字符串(前端传入)或Geoalchemy Geometry对象(数据库读取),自动转换为统一的Geometry类型。
  • 序列化输出:将数据库返回的Geometry对象转为WKT字符串,方便前端解析使用。
  • 空间操作支持:在SQLAlchemy查询中,可直接使用Geoalchemy2提供的空间函数(如ST_Intersects、ST_Within等)对geom字段执行空间操作,Schema的类型转换不影响数据库层面的空间计算。

内容的提问来源于stack exchange,提问作者Taraman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 05:07:36