Django2+PostGIS报错:无法比较F()与int()类型,求解决
Django 2 + PostGIS: 解决
unorderable types: F() < int()错误 我一眼就看出问题出在哪了——你在min(finder.preferred_radius, F('preferred_radius'))这里用了Python内置的min()函数,这可是个典型的「把数据库层面的操作拿到Python里做」的坑!
错误原因
Python的min()函数会尝试直接比较传入的两个值:一个是从数据库取出来的整数finder.preferred_radius,另一个是Django的F()表达式(它只是一个数据库查询的占位符,还没实际求值)。Python根本不知道怎么比较这俩完全不同类型的对象,自然就抛出unorderable types: F() < int()的错误了。
解决方案
我们得把「取两者最小值」的逻辑放到数据库层面去执行,用Django的Case和When表达式来实现这个逻辑,这样就能让PostgreSQL(搭配PostGIS)在数据库里完成比较,而不是在Python代码里瞎折腾。
修改后的代码如下:
from django.db.models import Case, When, F @api_view(['GET', ]) def fetch_proposals_for(request, nick_of_finder, current_latitude, current_longitiude): finder = get_object_or_404(TinderUser, nickname=nick_of_finder) finder_location = Point(float(current_longitiude), float(current_latitude)) # 用Case/When实现取两个半径的较小值 min_radius = Case( When(preferred_radius__lt=finder.preferred_radius, then=F('preferred_radius')), default=finder.preferred_radius ) candidates = TinderUser.objects.filter( last_location__distance_lte=(finder_location, D(km=min_radius)) ).distance(finder_location).order_by('distance') # 后续代码继续...
简单解释一下这段代码:
Case和When会生成数据库层面的条件判断:如果候选用户的preferred_radius比当前finder的小,就用候选用户的半径;否则就用finder的preferred_radius- 这样整个比较逻辑都在数据库里执行,不会再出现Python层面的类型不兼容问题
另外要注意,确保你的TinderUser模型里的preferred_radius字段是数值类型(比如IntegerField或FloatField),这样数据库才能正确做比较。
内容的提问来源于stack exchange,提问作者Arun Joseph
相关产品推荐
相关产品推荐

