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) |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Show comment
Hide comment
|
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
Note this is a packaging of http://stackoverflow.com/a/31715920/1373318