Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GeoDjango distance queries returning incorrect results

I just got GeoDjango up and running on my development machine. Problem is that I can't get a distance query to work correctly. No matter what SRID I use, the distance results are totally off. Here's an example.

>>> from django.contrib.gis.measure import D
>>> from app.models import Place
>>> from django.contrib.gis.geos import Point
>>> qs = Place.objects.all()
>>> point = Point(-118, 34)
>>> qs.filter(coordinates__distance_lte=(point, D(m=1)))
[<Place: 7-Eleven>, <Place: Arthur Murray Dance Studio>, <Place: Costco>, <Place: AMC Century City 15>, <Place: 24 Hour Fitness>, <Place: Ralphs>, <Place: Houston's Restaurant>, <Place: CVS/pharmacy>, <Place: Shaky Alibi>, <Place: Sephora>, <Place: Trader Joe's>]

The problem is that these places are much further than 1m away from point.

I tried playing around with it, but haven't had much luck. Here's an example with another SRID.

>>> qs = Place.objects.all().transform(3786)
>>> point = Point(-118, 34, srid=3786)
>>> qs.filter(coordinates__distance_lte=(point, D(m=1)))
[<Place: 7-Eleven>, <Place: Arthur Murray Dance Studio>, <Place: Costco>, <Place: AMC Century City 15>, <Place: 24 Hour Fitness>, <Place: Ralphs>, <Place: Houston's Restaurant>, <Place: CVS/pharmacy>, <Place: Shaky Alibi>, <Place: Sephora>, <Place: Trader Joe's>]

I have a feeling I'm just choosing the wrong SRIDs, but not a single one that I've run into online has worked, or given any response that is even moderately useful.

Any help is greatly appreciated!

like image 583
dwlz Avatar asked Jul 28 '11 03:07

dwlz


1 Answers

I hate to be answering my own question, but no one else stepped up to the plate and I figured out the solution.

I delved into PostGIS to isolate the issue to either the location database itself or to Django. So I converted the Django ORM query I had been using above into the ideal query that I would have expected the PostGIS backend to receive. To my surprise, the query that was being produced was equivalent to:

SELECT id
FROM app_place
WHERE ST_DWithin(coordinates, ST_SetSRID(ST_Point(-118, 34), 3768), 1);

That was the problem right there. The query I needed was:

SELECT id
FROM app_place
WHERE ST_Distance_Sphere(ST_SetSRID(ST_Point(-118, 34), 3768), coordinates) < 1;

I read through the Django source to figure out what was happening here, and I realized that I had set geography=True on my coordinates field. Apparently, this changes the PostGIS functions Django generates when creating the SQL query. It's undocumented, but here is the relevant section.

In short, if you're having this issue, remove geography=True from your model and you should be good to go.

like image 148
dwlz Avatar answered Oct 26 '22 18:10

dwlz