我正在尝试查找给定邮政编码的特定距离内的所有邮政编码。我这样做是通过使用自定义聚合函数计算距离,使用距离注释查询集,并根据“距离”字段过滤查询集。
聚合函数正确计算距离,注释正确地在查询集中创建“距离”字段。但是,筛选器始终返回空的查询集。当我使用其他字段(如'zipcode'或'state')进行过滤时,它可以正常工作,但当我使用带注释的'distance'值作为过滤器值时返回空。我做错了什么?
这是自定义聚合函数:
from django.db import models
from django.db.models import Aggregate
from django.db.models.sql.aggregates import Aggregate as AggregateImpl
class DistanceFromImpl(AggregateImpl):
sql_function = ''
is_computed = True
is_ordinal = True
sql_template = ('3959 * acos( cos( radians(%(t_lat)f) ) * cos( radians( latitude ) ) * '
'cos( radians( longitude ) - radians(%(t_lon)f) ) + sin( radians(%(t_lat)f) ) * '
'sin( radians( latitude ) ) )')
def __init__(self, col, target, **extra):
self.col = col
self.target = target
self.extra = extra
def _default_alias(self):
return '%s__%s' % (str(self.target), self.__class__.__name__.lower())
default_alias = property(_default_alias)
def add_to_query(self, query, alias, col, source, is_summary):
super(DistanceFrom, self).__init__(col, source, is_summary, **self.extra)
query.aggregate_select[alias] = self
def as_sql(self, qn, connection):
"Return the aggregate, rendered as SQL."
return self.sql_template % { 't_lon': self.target.longitude,
't_lat': self.target.latitude }
class DistanceFrom(Aggregate):
name="DistanceFromImpl"
def add_to_query(self, query, alias, col, source, is_summary):
aggregate = DistanceFromImpl(col, source=source, is_summary=is_summary, **self.extra)
query.aggregates[alias] = aggregate
我从这里抓住了这个和其他代码: https://github.com/elfsternberg/django-zipdistance/blob/master/zipdistance/models.py
我的邮政编码模型称为ZipDistance。我可以很容易地从给定的ZipDistance获得带有注释距离的查询集。所以这很好用:
>>> zip1 = ZipDistance.objects.get(zipcode='01234')
>>> qs = ZipDistance.objects.annotate(distance=DistanceFrom('zipcode', target=zip1))
>>> qs[1].distance
5 # Second entry in queryset is 5 miles away from zipcode '01234'
但按距离过滤总是返回空白:
>>> qs.filter(distance__lte=99999)
[]
我正在使用自己的fixture来填充我的数据库(这是MySQL)。问题可能是我使用的是Django 1.5版,而代码是为早期版本编写的。我只是不确定,我已经尝试了几天我能想到的一切。
答案 0 :(得分:0)
仍不确定导致此错误的原因,但我通过在方法中编写自己的SQL代码来解决这个问题:
from django.db import models, connection, transaction
from math import sin, cos, radians, acos
class ZipDistance(models.Model):
zipcode = models.CharField(max_length=5, unique=True)
state_short = models.CharField(max_length=2)
latitude = models.FloatField()
longitude = models.FloatField()
province = models.CharField(max_length=50)
state_long = models.CharField(max_length=20)
def get_zips_within(self, dist):
cursor = connection.cursor()
cursor.execute("""SELECT id, (
3959 * acos( cos( radians(%s) ) * cos( radians( latitude ) ) *
cos( radians( longitude ) - radians(%s) ) + sin( radians(%s) ) *
sin( radians( latitude ) ) ) )
AS distance FROM myapp_zipdistance
HAVING distance <= %s""",
[self.latitude, self.longitude, self.latitude, dist])
ids = [row[0] for row in cursor.fetchall()]
return ZipDistance.objects.filter(id__in=ids)
现在,我需要做的就是获取一定距离内的邮政编码列表如下:
>>> zip1 = ZipDistance.objects.get(zipcode='20001')
>>> zip_list = zip1.get_zips_within(dist=100)
这为我提供了华盛顿特区100英里内数据库中所有邮政编码的列表(邮政编码20001)