You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Django应用中实现连锁店位置搜索与产品查询功能

嘿,我来帮你一步步搞定这个Django门店搜索+产品展示的需求,从模型设计到功能实现,再到你需要学习的重点,都给你捋明白~

一、先搞定Store模型的location字段设计

别纠结存经纬度还是用第三方API了,直接用GeoDjango的PointField是最优解!原因很简单:

  • 它是Django官方提供的空间字段,专门用来存储经纬度坐标,支持原生的地理查询(比如距离计算、范围筛选)
  • 比自己手动存两个float字段(lat, lon)方便太多,不用写复杂的距离计算公式,也不容易出错

修改后的Store模型代码:

首先需要配置GeoDjango(后面会讲学习路径),然后调整模型:

from django.contrib.gis.db import models

class Store(models.Model):
    name = models.CharField(max_length=255)
    # PointField存储经纬度,SRID=4326是GPS通用的WGS84坐标系
    location = models.PointField(srid=4326)

    def __str__(self):
        return self.name
二、实现「按当前位置搜X公里内门店」的核心步骤

1. 获取用户当前位置

前端用HTML5的navigator.geolocation API就能拿到用户的经纬度,示例JS代码:

if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(
        (position) => {
            const lat = position.coords.latitude;
            const lon = position.coords.longitude;
            // 把经纬度传给后端搜索接口,这里radius是要搜索的公里数
            fetch(`/api/stores/search?lat=${lat}&lon=${lon}&radius=5`, {
                method: 'GET'
            })
            .then(res => res.json())
            .then(data => {
                // 渲染门店列表到页面
            });
        },
        (error) => {
            // 处理用户拒绝定位的情况,比如提供手动输入地址的选项
            alert('无法获取你的位置,请手动输入地址');
        }
    );
}

2. 后端实现距离查询

后端接收前端传的参数,用GeoDjango的查询API筛选符合距离要求的门店:

from django.contrib.gis.geos import Point
from django.contrib.gis.measure import D
from django.http import JsonResponse
from .models import Store

def search_stores(request):
    lat = float(request.GET.get('lat'))
    lon = float(request.GET.get('lon'))
    radius = float(request.GET.get('radius', 5))  # 默认搜索5公里内的门店

    # 注意:GeoDjango的Point是(经度, 纬度)的顺序
    user_point = Point(lon, lat, srid=4326)

    # 筛选X公里范围内的门店,按距离从近到远排序
    nearby_stores = Store.objects.filter(
        location__distance_lte=(user_point, D(km=radius))
    ).annotate(
        distance=models.Distance('location', user_point)
    ).order_by('distance')

    # 把结果转成JSON返回(如果用DRF可以用序列化器更规范)
    data = [
        {
            'id': store.id,
            'name': store.name,
            'distance': round(store.distance.km, 2)  # 保留两位小数显示距离
        } for store in nearby_stores
    ]

    return JsonResponse({'stores': data})
三、选择门店后查看在售产品

既然你已经完成了产品配置,假设Product模型和Store是关联的,比如:

class Product(models.Model):
    name = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    store = models.ForeignKey(Store, on_delete=models.CASCADE, related_name='products')

    def __str__(self):
        return self.name

那用户选择门店后,后端只要根据门店ID查询对应的产品即可:

def get_store_products(request, store_id):
    try:
        store = Store.objects.get(id=store_id)
        products = store.products.all()  # 用related_name反向关联查询产品
        data = [
            {
                'name': product.name,
                'price': str(product.price)
            } for product in products
        ]
        return JsonResponse({'products': data})
    except Store.DoesNotExist:
        return JsonResponse({'error': '门店不存在'}, status=404)
四、你需要学习的内容清单
  • GeoDjango基础:优先看Django官方文档的GeoDjango章节,重点掌握空间模型定义、PointField用法、空间查询API(比如distance_lteDistance注解)
  • 数据库空间扩展:如果用PostgreSQL,必须安装配置PostGIS(GeoDjango依赖它处理空间数据);开发测试用SQLite的话,启用Spatialite扩展即可
  • 前端地理定位:熟悉HTML5 navigator.geolocation的用法,以及定位失败的边界处理
  • Django数据返回:如果是前后端分离,学一下Django REST Framework(DRF)的序列化器;如果是传统模板渲染,掌握Django模板展示列表数据的方法
  • 性能优化:给Store的location字段加空间索引(GeoDjango会自动创建,但要确认数据库支持),避免数据量大时查询变慢
五、一些注意事项
  • 前端定位需要HTTPS(localhost除外),生产环境记得配置SSL证书
  • 一定要处理用户拒绝定位的情况,比如提供手动输入地址的备选方案(可以调用地理编码API把地址转成经纬度)
  • 测试时可以用固定的经纬度(比如某家达美乐的实际坐标)验证查询逻辑是否正确

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

火山引擎 最新活动