flask中需用geoip2+geolite2离线解析真实ip为经纬度,再用st_setsrid(st_makepoint(lon,lat),4326)转wkb;postgis空间查询须确保srid一致、建gist索引、用st_dwithin而非st_distance,并验证几何合法性。

Flask 中怎么把用户 IP 转成经纬度再存进 PostGIS
直接靠 Flask 拿不到真实地理位置,request.remote_addr 通常是代理 IP 或内网地址。得先做 IP 归属地解析,再转坐标——但别用免费 HTTP 接口轮询,容易被限流或返回粗略到城市级的坐标。
- 生产环境建议用
geoip2库 + MaxMind GeoLite2 数据库(离线查,快且稳定),配合 Nginx 的X-Forwarded-For头取真实客户端 IP - 查出的
city.location.latitude和city.location.longitude是 float,插入前要转成WKBElement:用func.ST_SetSRID(func.ST_MakePoint(long, lat), 4326) - 漏掉
ST_SetSRID是高频错误,PostGIS 默认不认坐标系,后续ST_DWithin会返回空或报错Operation on two geometries with different SRIDs
GeoAlchemy2 查询“5 公里内最近的 3 个门店”怎么写才不出错
不能直接用 Python 算欧氏距离,得交由 PostGIS 的空间函数处理,否则无法利用 GIST 索引,10 万条数据可能秒变全表扫描。
- 确保模型字段定义为
Geometry(geometry_type='POINT', srid=4326),并在数据库中为该字段建 GIST 索引:CREATE INDEX idx_stores_geom ON stores USING GIST (geom); - 查询必须用
ST_DWithin而非ST_Distance:前者能走索引,后者强制计算每行距离;单位是米,但输入坐标系必须是地理坐标(srid=4326)且用use_spheroid=True才准 - 示例语句:
Store.query.filter(func.ST_DWithin(Store.geom, point_wkb, 5000, use_spheroid=True)).order_by(func.ST_Distance(Store.geom, point_wkb)).limit(3)
为什么 ST_Intersects 总返回 False,明明地图上看着相交
大概率是坐标系或几何类型不匹配。GeoAlchemy2 不自动做投影转换,PostGIS 也不隐式 cast。
- 检查两边 SRID 是否一致:
ST_SRID(geom1)和ST_SRID(geom2),不同就用ST_Transform统一到 4326 或 3857 - 多边形数据如果来自前端 GeoJSON,注意
coordinates顺序:PostGIS 要外环逆时针(右手法则),否则ST_IsValid返回 False,ST_Intersects必然失效 - 用
ST_AsText(geom)在 psql 里看原始 WKT,比在 Python 里 print 更可靠——有时shapely加载时已静默修复了非法环
Flask-SQLAlchemy 和 GeoAlchemy2 混用时 migrate 报 Unknown geometry type
不是模型写错了,是 Alembic 不认识 Geometry 类型,生成 migration 时跳过空间字段,导致表结构缺失。
- 在
env.py的run_migrations_online前加一行:from geoalchemy2 import Geometry,否则 autogenerate 看不到自定义类型 - 若已有旧 migration 文件,手动在
op.create_table中补上sa.Column('geom', Geometry('POINT', srid=4326)),别删重跑 - PostGIS 扩展没启用也会触发同类错误:确认数据库里执行过
CREATE EXTENSION IF NOT EXISTS postgis;
空间查询的坑不在语法,而在数据源头——坐标系、精度、合法性,三者错一个,后面所有 ST_* 函数都可能静默失效或性能崩塌。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











