
从“一句话自动标点”到“地理围栏提醒”:我的 Django + Vue 地图实践分享
- Published on
目录:
- 1. 场景与动机:为什么重新做一张“自己的地图”?
- 2. 核心链路总览(一句话版)
- 3. 技术选型背后的取舍(为什么这样搭)
- 4. 数据获取:AI 如何“代替我去找坐标”
- 5. 地理围栏通知:为什么“简单”却高价值
- 6. 后端模型与前端展示如何配合
- 7. 交互与性能:一些避坑经验
- 8. 可复用的“最小实现包”清单
- 9. 想要“再往前走”可以做什么?
- 10. 读者可立即尝试的 5 个小练习
- 11. 一些真实的踩坑瞬间
- 12. 更多 & 延伸阅读
- 结语:地图是“连接器”
如果你也想:
- 搭一个“好看、顺手、可扩展”的自用/团队地图平台;
- 自动化收集兴趣点(而不是手敲 Excel / Notion);
- 做到靠近某个地点时手机自动提醒;
- 让 Django + Vue + 少量辅助工具就撑起一个完整链条;
那这篇内容应该能给你灵感。下面我会按“问题 → 方案 → 实现抓手 → 可复制性”展开。
1. 场景与动机:为什么重新做一张“自己的地图”?
我沉迷浏览建筑/场所资讯(专业网站 + 社交平台)。每天看到“这儿开了新咖啡”“那儿竣工了个漂亮剧院”,传统收藏方式的问题是:
传统方式 | 痛点 |
---|---|
App 内收藏 | 数据被平台“锁住”,难以批量导出 / 分析 |
手动复制地址再查地图 | 步骤多、易错、效率低 |
零散截图或链接 | 不结构化,后期无法空间分析 |
于是目标非常清晰:把“我看到的一切有空间含义的资讯”→ 结构化地落成“项目点(Point)+ 可选范围(Polygon)+ 丰富属性”。
2. 核心链路总览(一句话版)
资讯来源(网页 / 文本 / 链接) → AI 解析提取地点语义 → 地理编码工具获取标准地址与经纬度 → 校验 / 补充属性 → 写入数据库(ProjectData + Geofence)→ 前端地图渲染 + 交互(收藏 / 访问 / 忽略)→ 可选:进入围栏触发通知。
我在AI代替手动搜索:我如何只用“一句话”,就可以在地图上自动标点 | Renhai实验室一文中说明了我用AI替代我标点的想法,感兴趣的可以看看。
关键点:大量“枯燥手工”被 AI + 地理编码外部工具替代,人做“判断 + 调整”而不是“重复搬运”。
3. 技术选型背后的取舍(为什么这样搭)
模块 | 选择 | 备选 | 取舍理由 |
---|---|---|---|
后端 | Django + GeoDjango + DRF | FastAPI / Node | Geo 模型成熟 + 管理后台天然加成 |
存储 | PostGIS | 纯 Postgres + 手写几何 | 省去大量空间运算轮子 |
前端 | Vue 3 + MapLibre GL | React + Mapbox GL | 熟悉 + MapLibre 开源不锁定 Token |
数据获取 | AI Agent + 地理编码 MCP 工具 | 全人工 | 降低重复劳动、速度数量级提升 |
通知 | 地理围栏 + 位置上报 | 定时轮询 | 精准触发、减少无效请求 |
静态资源 | S3/MinIO | 本地文件 | 便于后期云化与多实例 |
django的后端非常完善,方便管理,后台页面:
经验:不要一上来追“最炫栈”,先保留扩展点(比如预留矢量瓦片 / 聚合),再循序渐进。
4. 数据获取:AI 如何“代替我去找坐标”
详细实操在另一篇《AI 代替手动搜索:我如何只用“一句话”,就可以在地图上自动标点》。这里浓缩关键做法:
- 我把整段文章 / 截图 OCR 文本 / 社交笔记内容丢给一个具“工具调用”能力的 Agent(Dify React Agent)。
- Prompt 约束:必须先抽取候选地点名称(含上下文,如“西岸大剧院”),不要直接编造经纬度。
- Agent 调用 MCP 格式的 geocoding 工具(如 AMap 高德 mcp 工具)→ 返回结构化 JSON(含经纬度 / 省市区 / 原始地址)。
- 二次规整:补充分类、来源链接、抓取时间戳、潜在标签(由 AI 归纳)。
- 写入数据库:ProjectData(点) + 可选生成围栏(依据半径缓冲或后续人工精修)。
好处:
- 单条信息处理从 60
120 秒 → 510 秒(含人工 glance)。 - 规范字段命名,后续统计 / 空间过滤不再返工。
- 可复用:只需换一个 geocode 工具即可适配其它国家/城市。
心得:一开始就定义“最终落库 JSON schema”极其重要,AI 输出更稳定、调试也更快。
5. 地理围栏通知:为什么“简单”却高价值
使用场景:
- 走到之前标记的“想去”的咖啡店附近 → 提醒“要不要顺路?”
- 靠近某个建筑项目 → 推出最近更新的照片 / 进度。
本质:判断“设备位置点 P 是否进入/离开 Polygon G” + 状态去抖(避免 GPS 抖动导致反复进出)。
最小实现(伪流程):
- 客户端/设备定期上传当前坐标(节流 + 最小移动距离阈值)。
- 后端用 PostGIS 进行
ST_Contains(geofence.geom, ST_SetSRID(ST_Point(lon,lat),4326))
判断。 - 维护一张
device_geofence_state(device_id, geofence_id, in_state, updated_at)
。 - 状态从 False→True 触发“进入”通知;True→False 触发“离开”。
- 发送渠道:Web 推送 / App / Home Assistant / Email(按你的生态)。
去噪技巧:
问题 | 解决 | 说明 |
---|---|---|
GPS 漂移反复触发 | 加最小停留时间 / 距离阈值 | 进入后先计时,再确认 |
大面积围栏价值低 | 分层:核心区 + 缓冲区 | 不同区触发不同级别提示 |
通知疲劳 | 设冷却(cooldown) | 同一围栏 X 分钟内最多一次 |
一句话总结:地理围栏 ≠ 复杂黑科技;它就是“点在不在多边形里 + 状态变化记录”。
6. 后端模型与前端展示如何配合
关键数据模型(简化概念版):
模型 | 作用 | 关键字段 |
---|---|---|
ProjectData | 结构化地点/项目 | name, category, lon/lat, city, features, geofence(one-to-one) |
Geofence | 多边形范围 | polygon, active, source_id |
LocationUpdate | 设备位置轨迹 | device_id, point, timestamp |
DeviceGeofenceState | 进出状态 | device_id, geofence_id, in_state |
Favorite / Visited / Ignored | 用户行为 | user_id + object_id + ts |
前端渲染策略:
- 初始加载当前视窗范围内项目(加“边界缓冲”避免轻微拖动就刷新)。
- 使用 MapLibre 图层区分:基础底图 / 项目点 / 围栏多边形 / 交互高亮。
- 收藏 / 已访问等“用户态”通过样式(颜色 / 边框)即时反馈。
- 点位较多时预留后续聚合(cluster)或服务端瓦片化的接口。
7. 交互与性能:一些避坑经验
方面 | 问题 | 措施 | 效果 |
---|---|---|---|
频繁移动地图 | 请求风暴 | 防抖 + 视窗扩展缓存 | 请求次数明显下降 |
点位刷新闪烁 | 重绘全部 | diff 更新 / 分层管理 | 视觉更稳定 |
围栏过密 | 视觉噪声 | 缩放级别过滤 | 减少遮挡 |
数据获取延迟 | 首屏空白 | 骨架态 / loading 提示 | 心理预期良好 |
8. 可复用的“最小实现包”清单
把下面几块拼起来,你就能快速复制一个类似平台:
- 后端:Django + DRF + GeoDjango + PostGIS(模型 + 基础 CRUD)
- 前端:Vue + MapLibre + Axios(点/围栏图层 & 交互面板)
- AI 采集:Dify React Agent + geocode MCP 工具(输出统一 JSON)
- 围栏通知:定时/事件位置上报 + ST_Contains + 状态表 + 通知适配器
- 用户行为:收藏 / 访问 / 忽略 统一抽象(多做一个通用 mixin/表结构更好)
- 脚本层:导入、批更新、数据修正(保持“可重复”而非手点)
9. 想要“再往前走”可以做什么?
方向 | 思路 | 价值 |
---|---|---|
瓦片化 | martin / tippecanoe 预处理 | 海量点加载提速 |
服务端聚合 | H3 / quadbin 栅格聚类 | 分布洞察更直观 |
语义标签挖掘 | LLM 继续抽特征 | 形成“语义地图” |
实时性 | WebSocket / SSE | 轨迹 & 动态提醒 |
推荐 | 根据足迹/收藏协同过滤 | 主动提示“可能感兴趣” |
10. 读者可立即尝试的 5 个小练习
- 写一个最小 Django 模型:
Place(name, point)
,用 DRF 暴露 List API,在 MapLibre 上渲染。 - 尝试给地点增加一个
radius
字段,生成临时圆形围栏,并计算“是否在范围内”。 - 用任意 LLM + geocode API:输入一句“在上海黄浦江畔的西岸大剧院”,让它返回
{name, lon, lat, city}
。 - 实现一个“进入围栏只提醒一次/24h”的逻辑。
- 给前端点位加“收藏”按钮,状态写回后端,再次加载地图自动带出样式。
11. 一些真实的踩坑瞬间
- 刚开始地图视图一移动就请求 → CPU 飙高 + 点位闪烁,立刻引入防抖与扩展缓存。
- 早期围栏来源混乱(手画风格天差地别),后来统一:自动缓冲 → 人工精修 → 版本留存。
- AI 有时会“自信杜撰”地址:解决方案是必须走外部 geocode 工具、抽取 & 查询严格分离。
- 通知一开始“连环轰炸”,加了冷却 + 停留时间后体验才正常。
12. 更多 & 延伸阅读
- AI代替手动搜索:我如何只用“一句话”,就可以在地图上自动标点 | Renhai实验室
- 主仓库
README.md
(部署 / 模型 / API 结构) - PostGIS 文档:空间函数 ST_Contains / ST_DWithin / ST_Intersection
- MapLibre GL 官方文档:图层与数据源管理
结语:地图是“连接器”
当你把“看到的信息 → 结构化 → 空间化 → 可触发”这条链路打通后,地图不再只是“展示”,而是一个可以编排各种自动化的“连接器”。
希望这篇文章能启发你:
- AI + 地理编码 = 个人/团队专属地理数据库的加速器
- 围栏通知 = 极低实现门槛的高价值功能
- Django + Vue 完全可以优雅支撑一个实践级 GIS 产品雏形
欢迎基于这些思路做你自己的版本。如果你也做出了有趣的“地图工作流”,欢迎分享。🙌