1

我正在尝试查找给定邮政编码一定距离内的所有邮政编码。我通过使用定制的聚合函数计算距离,用距离注释查询集,并根据该“距离”字段过滤查询集来做到这一点。

聚合函数正确计算距离,注释在查询集中正确创建“距离”字段。但是,过滤器总是返回一个空的查询集。当我使用“邮政编码”或“状态”等其他字段进行过滤时,它工作正常,但当我使用带注释的“距离”值作为过滤器值时返回空。我究竟做错了什么?

这是自定义聚合函数:

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)
[]

我正在使用自己的装置来填充我的数据库(即 MySQL)。问题可能是我使用的是 Django 1.5 版,并且代码是为早期版本编写的。我只是不确定,几天来我一直在尝试我能想到的一切。

4

1 回答 1

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)

于 2013-12-22T14:11:14.897 回答