Instantly share code, notes, and snippets.

@rchrd2 /models.py
Last active Jan 12, 2018

Embed
What would you like to do?
Django object manager with Haversine distance annotation method (aka filter by distance with mysql)
from django.db import models
from with_distance_manager import WithDistanceManager
class Foo(models.Model):
longitude = models.DecimalField(max_digits=19, decimal_places=10, null=True)
latitude = models.DecimalField(max_digits=19, decimal_places=10, null=True)
objects = WithDistanceManager()
class WithDistanceManager(models.Manager):
def with_distance(self, latitude, longitude):
"""
Returns a QuerySet of locations annotated with their distance from the
given point. This can then be filtered.
Usage:
Foo.objects.within(lat, lon).filter(distance__lt=10).count()
@see http://stackoverflow.com/a/31715920/1373318
"""
class Sin(Func):
function = 'SIN'
class Cos(Func):
function = 'COS'
class Acos(Func):
function = 'ACOS'
class Radians(Func):
function = 'RADIANS'
radlat = Radians(latitude) # given latitude
radlong = Radians(longitude) # given longitude
radflat = Radians(F('latitude'))
radflong = Radians(F('longitude'))
# Note 3959.0 is for miles. Use 6371 for kilometers
Expression = 3959.0 * Acos(Cos(radlat) * Cos(radflat) *
Cos(radflong - radlong) +
Sin(radlat) * Sin(radflat))
return self.get_queryset()\
.exclude(latitude=None)\
.exclude(longitude=None)\
.annotate(distance=Expression)
@rchrd2

This comment has been minimized.

Show comment
Hide comment
@rchrd2
Owner

rchrd2 commented Jan 2, 2017

Note this is a packaging of http://stackoverflow.com/a/31715920/1373318

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment