Initial commit of working zipdistance.
This commit is contained in:
commit
d645ccdd47
|
@ -0,0 +1,12 @@
|
||||||
|
*.pyc
|
||||||
|
*.rej
|
||||||
|
*.orig
|
||||||
|
*.pyo
|
||||||
|
*#
|
||||||
|
.#*
|
||||||
|
.DS_Store
|
||||||
|
*~
|
||||||
|
indieflix/stages/chi/
|
||||||
|
indieflix/static/avatars/
|
||||||
|
*.xcf
|
||||||
|
common/ctctwspylib/.cache
|
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2008 Elf M. Sternberg and all contributors
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE AND DATA IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||||
|
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,52 @@
|
||||||
|
==============================
|
||||||
|
django-zipdistance
|
||||||
|
==============================
|
||||||
|
|
||||||
|
django-zipdistance is a simple application to find the distance
|
||||||
|
between any two zip codes. The fixture provided with this application
|
||||||
|
is derived from the Year 2000 Zip Code Tabulation Area (ZCTA) tables
|
||||||
|
provided by the US Census Bureau. The Census Bureau notes:
|
||||||
|
|
||||||
|
ZCTAs are generalized area representations of U.S. Postal Service
|
||||||
|
(USPS) ZIP Code service areas. In most instances the ZCTA code
|
||||||
|
equals the ZIP Code for an area. Some ZIP Codes represent very
|
||||||
|
few addresses (sometimes only one) and therefore will not appear
|
||||||
|
in the ZCTA database. ZCTA is a trademark of the U.S. Census
|
||||||
|
Bureau; ZIP Code is a registered trademark of the U.S. Postal
|
||||||
|
Service.
|
||||||
|
|
||||||
|
In short, the ZCTAs most likely, but are not guaranteed to, correspond
|
||||||
|
with ZIP Codes for any given address. In testing, this database
|
||||||
|
proved to be entirely acceptable for most of the United States. But
|
||||||
|
just to make sure, I repeat: THE SOFTWARE AND DATA FILES ARE PROVIDED
|
||||||
|
"AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||||
|
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||||
|
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
-----------------------------
|
||||||
|
Standard Usage:
|
||||||
|
|
||||||
|
Find all the zipcodes within 50 miles:
|
||||||
|
|
||||||
|
target = Zipmap.objects.get(zipcode = zip_form.cleaned_data['zipcode1'].strip())
|
||||||
|
zips = Zipmap.objects.distance_from(target, 50)
|
||||||
|
|
||||||
|
Find the distance between two zipcodes:
|
||||||
|
|
||||||
|
zip1 = Zipmap.objects.get(zipcode = zip_form.cleaned_data['zipcode1'].strip())
|
||||||
|
zip2 = Zipmap.objects.get(zipcode = zip_form.cleaned_data['zipcode1'].strip())
|
||||||
|
zip1.distance_between(zip_2)
|
||||||
|
|
||||||
|
Find all the stores within a given distance.
|
||||||
|
|
||||||
|
zips = Zipmap.objects.distance_from(target, 50)
|
||||||
|
stores = Store.objects.get(zipcode__in = [z.zipcode for z in zips])
|
||||||
|
|
||||||
|
That last one's not terribly efficient. If you used the ZipMap as a
|
||||||
|
way of storing zipcodes, you could probably come up with something
|
||||||
|
smarter.
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Django==1.2
|
|
@ -0,0 +1,26 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
setup (
|
||||||
|
name='django-zipdistance',
|
||||||
|
version='0.1',
|
||||||
|
description='A zip code distance application for Django.',
|
||||||
|
author='Elf M. Sternberg',
|
||||||
|
author_email='elf.sternberg@gmail.com',
|
||||||
|
url='http://github.com/elfsternberg/django-zipdistance/',
|
||||||
|
license='MIT License',
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 3 - Alpha',
|
||||||
|
'Environment :: Plugins',
|
||||||
|
'Framework :: Django',
|
||||||
|
'Intended Audience :: Developers',
|
||||||
|
'License :: OSI Approved :: BSD License',
|
||||||
|
'Programming Language :: Python',
|
||||||
|
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||||
|
],
|
||||||
|
package_data = {
|
||||||
|
'': ['*.yaml.gz']
|
||||||
|
},
|
||||||
|
packages=find_packages(),
|
||||||
|
)
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Copyright 2010 by Elf M. Sternberg. All rights not expressly granted
|
||||||
|
# herein are reserved.
|
||||||
|
#
|
||||||
|
# Created in the United States of America.
|
||||||
|
#
|
||||||
|
# This digital media is protected by U.S. and international copyright
|
||||||
|
# and intellectual property laws. Unless otherwise specified, all
|
||||||
|
# information and screens appearing as part of this digital medium,
|
||||||
|
# including software, services, documents, text, images, icons, and
|
||||||
|
# logos design; the selection, assembly, arrangement, and design
|
||||||
|
# thereof; and the code that enables its presentation, are the sole
|
||||||
|
# property of Elf M. Sternberg.
|
||||||
|
|
||||||
|
# Permission is hereby granted, free of charge, to any person
|
||||||
|
# obtaining a copy of this software and associated documentation files
|
||||||
|
# (the "Software"), to deal in the Software without restriction,
|
||||||
|
# including without limitation the rights to use, copy, modify, merge,
|
||||||
|
# publish, distribute, sublicense, and/or sell copies of the Software,
|
||||||
|
# and to permit persons to whom the Software is furnished to do so,
|
||||||
|
# subject to the following conditions:
|
||||||
|
|
||||||
|
# The above copyright notice and this permission notice shall be
|
||||||
|
# included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
# THE SOFTWARE AND DATA IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
Binary file not shown.
|
@ -0,0 +1,74 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ZipDistanceManager(models.Manager):
|
||||||
|
|
||||||
|
def distance_from(self, target, limit = 0):
|
||||||
|
qs = self.annotate(distance = DistanceFrom('zipcode', target = target))
|
||||||
|
if bool(limit):
|
||||||
|
qs = qs.filter(distance__lte = float(limit))
|
||||||
|
qs = qs.order_by('distance')
|
||||||
|
return qs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ZipDistance(models.Model):
|
||||||
|
state = models.CharField(max_length = 2)
|
||||||
|
zipcode = models.CharField(max_length = 5, unique = True)
|
||||||
|
latitude = models.FloatField()
|
||||||
|
longitude = models.FloatField()
|
||||||
|
|
||||||
|
objects = ZipDistanceManager()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['zipcode']
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return '%s:%s' % (self.state, self.zipcode)
|
||||||
|
|
||||||
|
def distance_between(self, other):
|
||||||
|
return self.__class__.objects.distance_from(self).get(zipcode = other.zipcode).distance
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
"""
|
||||||
|
This file demonstrates two different styles of tests (one doctest and one
|
||||||
|
unittest). These will both pass when you run "manage.py test".
|
||||||
|
|
||||||
|
Replace these with more appropriate tests for your application.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
class SimpleTest(TestCase):
|
||||||
|
def test_basic_addition(self):
|
||||||
|
"""
|
||||||
|
Tests that 1 + 1 always equals 2.
|
||||||
|
"""
|
||||||
|
self.failUnlessEqual(1 + 1, 2)
|
||||||
|
|
||||||
|
__test__ = {"doctest": """
|
||||||
|
Another way to test that 1 + 1 is equal to 2.
|
||||||
|
|
||||||
|
>>> 1 + 1 == 2
|
||||||
|
True
|
||||||
|
"""}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
# Create your views here.
|
Loading…
Reference in New Issue