Django REST Framework实现按距离筛选用户时出现不可迭代错误
错误原因及修复方案
你遇到的'RenameAttributes' object is not iterable报错直接原因是:DRF的filter_backends属性要求传入可迭代的列表/元组类型,你直接赋值了单个过滤器类,DRF遍历过滤器后端时无法解析该对象就抛出了不可迭代错误。
除此之外你的代码还有多处逻辑错误,全部修复方案如下:
1. 修正过滤器后端配置
首先要保证你定义的字段过滤(性别、姓名)和自定义距离过滤都能生效,修改UserListView中的配置:
# 先导入DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend class UserListView(generics.ListAPIView): queryset = User.objects.all() serializer_class = UserSerializer filterset_class = UserFilter # 改成列表形式,同时保留两个过滤后端 filter_backends = [CustomFilter, DjangoFilterBackend]
2. 修正字段大小写错误
你的User模型里定义的经纬度字段是全小写的latitude、longitude,你代码里写的大写开头的Longitude、Latitude属于属性名错误,会直接抛出属性不存在的异常,全部改成小写:
current_user_long = request.user.longitude current_user_lat = request.user.latitude alluser_long = user.longitude alluser_lat = user.latitude
3. 修正Python语法错误
Python列表没有push方法,添加元素要用append:
newQueryset.append(user)
4. 修正过滤逻辑和类型转换
前端传的distance是字符串类型,要先转成数值再比较;同时你当前的判断逻辑是反的,要保留距离小于等于指定范围的用户:
def filter_queryset(self, request , queryset,view): newQueryset = [] distparam = request.GET.get('distance') if distparam: # 先做类型校验,避免非法参数报错 try: distparam = float(distparam) except ValueError: return queryset current_user_long = request.user.longitude current_user_lat = request.user.latitude for user in queryset: alluser_long = user.longitude alluser_lat = user.latitude # 注意要处理用户经纬度为空的情况,避免计算报错 if not alluser_long or not alluser_lat: continue distance = calculateDistance(current_user_long, current_user_lat, alluser_long, alluser_lat) # 保留距离小于等于指定值的用户 if distance <= distparam: newQueryset.append(user) return newQueryset return queryset
可选性能优化
你现在的实现是遍历全表用户计算距离,数据量大时性能极低,且返回普通列表会导致DRF的分页、排序等功能失效,建议改用数据库自带的空间计算函数,直接在SQL层面过滤,返回Queryset对象即可兼容所有ORM操作。
内容的提问来源于stack exchange,提问作者stevencharr
相关产品推荐
相关产品推荐

