tags:

views:

297

answers:

2

I am trying to implement a proximity search based on latitude and longitude using Django and Postgresql. Here's the abstract version of the Model I have.

class Item(models.Model):
"""docstring for Item"""
uuid = UUIDField(primary_key=True, auto=True)
name = models.CharField(_("name"), max_length=200)
address = models.CharField(_('street address'), max_length=255, blank=True, null=True)
location = models.CharField(_('location'), max_length=40, blank=True, null=True)

@property
def geo_distance(self, location=None):
    if location is not None:
        cursor = connection.cursor()
        cursor.execute("SELECT geo_distance(CAST('%s')) AS POINT, CAST('%s') AS POINT)" % 
            self.location, location)
        return round(float(cursor.fetchone() * 1.621371192237), 2)

I want to be able to do something like this in views.py:

items = Item.objects.filter(name__istartwith="Anything")
results = []
for item in items:
    results.append({
        'name': item.name, 
        'distance': item.geo_distance("(11.23123, -12.123213)")
    })

I realize that this is not the best approach. Any suggestions welcome.

+1  A: 

If you a search based on latitude and longitude I would recommend you GeoDjango. To calculate distance between a two point or surrounding area from point X you can use Haversine formula. It better to write the distance calculation by using procedure. To my knowledge django doesn't support creating procedures, I made some benchmark in terms of calculating distance, i found procedures to be faster rather than calculating on the django end. Good Luck.

Prashanth
Thanks Prashanth for your suggestions. I will surely look further into GeoDjango. For now, I used Geopy to solve my problem. Its geocoding and distance calculation modules were quite helpful.
A: 

Well, your code isn't horrible. I imagine that you are concerned with performance because of the item.geo_distance() execution inside a for iteration? It doesn't matter, this is going to have to be calculated at some time. You solution is ok, but here are a few other pointers:

  • Use geopy (or geodjango)
  • Be sure to filter your data at the source (database).

Regarding the second point, filtering your data. I see that you are filtering on name, which means that's you aren't using distance to filter. If you did want to use distance from a point as the filter (eg, nothing more than 40 miles), then you get into some new problems which geopy and geodjango can help with. The common solution here is to approximate the distance (in a square), filter the data based on this approximation, and then calculate the exact distance.

marcc
Thanks marcc for taking time. Geopy seems to be what I need and I've incorporated it in my project. I forgot to include the geo_distance as filter but that's one of the requirements. I accomplished that using Geopy's distance calculation module. Filtering it at database level seemed to be inaccurate and slower by couple hundred ms compared to Geopy.
Nice! I finished a django / geopy project up a few months ago. Use the geopy calculations to power an API which is consumed by an iPhone app. Works like a charm.
marcc