基于类视图的DRF GET请求传参及GeoDjango查询问题
解决你的Django REST API Geo查询问题
不用切换到函数视图,咱们用ModelViewSet就能完美搞定这两个问题,下面一步步来:
问题1:request未定义的解决办法
你不能直接在类属性里访问request,因为类初始化的时候还没有请求上下文。正确的做法是重写get_queryset()方法——这个方法在每次请求处理时都会被调用,里面可以通过self.request拿到当前请求对象。
问题2:GET请求的参数获取方式
DRF里GET请求的查询参数(就是URL里?后面的部分)要从request.query_params里获取,而不是request.data(后者确实只针对POST/PUT/PATCH这类带请求体的方法)。
完整的代码实现
from django.contrib.gis.geos import Point from django.contrib.gis.measure import D from rest_framework import viewsets from rest_framework.exceptions import ValidationError class ModelViewSet(viewsets.ModelViewSet): # 留一个基础queryset作为降级方案,比如参数缺失时返回全部数据 queryset = Model.objects.all() def get_queryset(self): # 从URL查询参数中取值,注意转换数据类型,同时处理参数缺失的情况 radius_str = self.request.query_params.get('radius') longitude_str = self.request.query_params.get('longitude') latitude_str = self.request.query_params.get('latitude') # 校验必要参数是否齐全 if not all([radius_str, longitude_str, latitude_str]): raise ValidationError("请提供完整的radius、longitude和latitude参数") try: # 字符串转数字,避免类型错误 radius = float(radius_str) longitude = float(longitude_str) latitude = float(latitude_str) except ValueError: raise ValidationError("radius、longitude和latitude必须是有效的数字格式") # 创建Point对象,注意GeoDjango的坐标顺序是(经度, 纬度),同时指定坐标系(这里用常用的WGS84) location = Point(longitude, latitude, srid=4326) # 按距离过滤结果,并按距离排序 queryset = Model.objects.filter( location__distance_lte=(location, D(m=radius)) ).distance(location).order_by('distance') return queryset
额外注意事项
- 确认你的
Model中location字段是PointField类型,且已经正确配置GeoDjango环境(比如数据库开启空间扩展、安装了依赖的地理库)。 - 如果想更规范地做参数校验,可以结合DRF的
FilterSet或者自定义序列化器来实现,上面的代码已经能解决核心需求。 srid=4326是GPS常用的WGS84坐标系,如果你的数据用的是其他坐标系,记得对应修改这个值。
内容的提问来源于stack exchange,提问作者GRS
相关产品推荐
相关产品推荐

