Skip to content

Instantly share code, notes, and snippets.

@devangmundhra
Created January 16, 2016 06:49
Show Gist options
  • Save devangmundhra/a42845095f093f23ecd5 to your computer and use it in GitHub Desktop.
Save devangmundhra/a42845095f093f23ecd5 to your computer and use it in GitHub Desktop.
Finding venues within a radius (relies on PostgresSQL PostGIS)
"""
This file exposes a function to convert a GET request with location and radius into a GEOS object to be able to run Postgres query on it
"""
from geo import geocode_location
def bounding_circle(get_location_params):
"""
get_location_params- string that consists of comma separated query param "location name,radius", something like "Connaught Place,10"
radius in km
"""
try:
param_list = get_location_params.split(',')
# Get lng, lat from geocode method
lng, lat = geocode_location(param_list[0])
# Sent latidude,longitude,radius
return Point(lng, lat), float(param_list[1])
except (IndexError, AttributeError, ValueError):
return None, 0
"""
This file exposes two functions-
1. to use a crude bounding box method to get min/max coordinates for a radius when an advanced DB like Postgres is not available
2. to convert any address into latitude and longitude using Google's Geocoding API
"""
def calc_bounding_box(lat, lon, radius, use_miles=True):
""" retval -> lat_min, lat_max, lon_min, lon_max
Calculates the max and min lat and lon for an area.
It approximates a search area of radius r by using a box
For further details:
http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates (section 3.3)
For testing output
http://www.getlatlon.com/
"""
# d = distance
# R = Radius of sphere (6378.1 km or 3,963.1676 miles)
# r = d/R angular radius of query circle
R_MILES = 3963.1676
R_KM = 6378.1
lat = float(math.radians(lat))
lon = float(math.radians(lon))
radius = float(radius)
R = use_miles and R_MILES or R_KM
r = radius / R
lat_T = math.asin( math.sin(lat) / math.cos(r) )
delta_lon = math.asin( math.sin(r) / math.cos(lat) )
lon_min = math.degrees(lon - delta_lon)
lon_max = math.degrees(lon + delta_lon)
lat_min = math.degrees(lat - r)
lat_max = math.degrees(lat + r)
return lat_min, lat_max, lon_min, lon_max
def geocode_location(location, full=False):
"""
Use google geocode library
"""
key = getattr(settings, 'GOOGLE_MAPS_V3_APIKEY', None)
location = urllib.quote_plus(location.encode('utf8'))
if key:
request = "https://maps.googleapis.com/maps/api/geocode/json?address=%s&sensor=false&key=%s" % (location, key)
else:
request = "https://maps.googleapis.com/maps/api/geocode/json?address=%s&sensor=false" % (location)
data = urllib.urlopen(request).read()
dlist = json.loads(data)
"""
Find the latitude and longiture, and more information if full=True
"""
if dlist['status'] == "OK":
if full:
result = {
'lng': float(dlist['results'][0]['geometry']['location']['lng']),
'lat': float(dlist['results'][0]['geometry']['location']['lat']),
'region': _get_location_address_parameter(dlist, ['administrative_area_level_1', 'administrative_area_level_2']),
'country': _get_location_address_parameter(dlist, ['country']),
'city': _get_location_address_parameter(dlist, ['postal_town']),
}
return result
else:
lng = float(dlist['results'][0]['geometry']['location']['lng'])
lat = float(dlist['results'][0]['geometry']['location']['lat'])
return (lat, lng)
else:
if full:
return {}
return (0, 0)
"""
This file exposes a method that gets the GET request and returns a list of merchants that satisfy the location filter
"""
def merchant_location_search(get_params_location):
center, radius = bounding_circle(get_params_location)
if not center:
return Merchants.objects.none()
else:
merchants = Merchant.objects.filter(location__distance_lte=(center, D(km=radius)))
return merchants
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment