Last active
February 14, 2022 08:15
-
-
Save rchrd2/5e0b014640a459a14ef038975d2a3683 to your computer and use it in GitHub Desktop.
Django object manager with Haversine distance annotation method (aka filter by distance with mysql)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note this is a packaging of http://stackoverflow.com/a/31715920/1373318