""" 一次性脚本:从 PostgreSQL 导出静态底图为 GeoPackage 文件。 运行一次即可,之后服务直接读本地 GPKG。 用法: python -m app.script.export_static_layers """ import os import sys import time # 确保项目根目录在 sys.path 中 project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) if project_root not in sys.path: sys.path.insert(0, project_root) import geopandas as gpd from sqlalchemy import create_engine from config import settings # GPKG 输出目录(相对于项目根目录) GPKG_DIR = os.path.join(project_root, getattr(settings, "QGIS_GPKG_DIR", "app/data/gpkg")) # 静态图层定义: {显示名: (schema.table, geom_column, srid)} STATIC_LAYERS = { "水库": ("qgis.rivers", "Geometry", 0), "市州驻地": ("qgis.sx_capital", "geometry", 0), "河流": ("qgis.river", "Geometry", 0), "active_fault": ("qgis.active_fault", "Geometry", 0), "陕西省": ("qgis.sx", "Geometry", 0), "乡镇驻地": ("qgis.sx_street", "dgeom", 0), "区县驻地": ("qgis.sx_xa_county", "Geometry", 0), "县界": ("qgis.sx_xa_county_boundary", "Geometry", 0), "周边区县": ("qgis.sx_zb_county_boundary", "Geometry", 0), "周边市州": ("qgis.sx_zb_city", "Geometry", 4326), "周边县区": ("qgis.sx_zb_county", "Geometry", 0), "traffic_expressway": ("qgis.traffic_expressway", "Geometry", 0), "traffic_provincial": ("qgis.traffic_provincial", "Geometry", 0), "traffic_railway": ("qgis.traffic_railway", "Geometry", 0), "traffic_township": ("qgis.traffic_township", "Geometry", 0), "traffic_trunk_line": ("qgis.traffic_trunk_line", "Geometry", 0), } def export_layers(): os.makedirs(GPKG_DIR, exist_ok=True) conn_str = ( f"postgresql://{settings.DB_USER}:{settings.DB_PASSWORD}" f"@{settings.DB_HOST}:{settings.DB_PORT}/{settings.DB_NAME}" ) engine = create_engine(conn_str) for layer_name, (table_ref, geom_col, srid) in STATIC_LAYERS.items(): t0 = time.time() schema, table = table_ref.split(".", 1) print(f"导出 {layer_name} ({table_ref}) ...", end=" ", flush=True) try: sql = f'SELECT * FROM "{schema}"."{table}"' gdf = gpd.read_postgis(sql, engine, geom_col=geom_col) if srid and srid > 0: gdf = gdf.set_crs(epsg=srid, allow_override=True) elif gdf.crs is None: gdf = gdf.set_crs(epsg=4326) gpkg_path = os.path.join(GPKG_DIR, f"{table}.gpkg") gdf.to_file(gpkg_path, driver="GPKG") print(f"✓ {len(gdf)} 行, {time.time() - t0:.1f}s") except Exception as e: print(f"✗ 失败: {e}") engine.dispose() print(f"\n导出完成!文件目录: {GPKG_DIR}") if __name__ == "__main__": export_layers()