2

I am trying to retrieve some posts depending on their proximity geographically.
As you can see in the code I am using GeoDjango and the code is executed within a view.
The issue is that the distance filter seems to be completely disregarded.

When I check the distances on the queryset I get the expected distances (1m and 18km) but the 18km post should not have been retrieved.

def get(self, request, format=None):
    latlon=request.query_params
    pnt = GEOSGeometry('SRID=28992;POINT(%s %s)'%(latlon['lat'],latlon['lon']))
    posts = Post.objects.filter(point__distance_lte=(pnt, D(km=1)))
    serialized = PostSerializer(posts, many=True)
    for post in posts:
        distance = pnt.distance(post.point)
        print("Km distance:",distance * 100)
    return JsonResponse(serialized.data, safe=False)

Result:

Km distance: 0.00015231546206626192
Km distance: 18.317378752081577
[18/Jul/2017 13:24:35] "GET /api/posts/?lon=5.8372264&lat=51.8125626 HTTP/1.1" 200 144
John Moutafis
  • 22,254
  • 11
  • 68
  • 112
Evan
  • 1,683
  • 7
  • 35
  • 65

2 Answers2

2

I believe that your problem arises from the reverse order of lat and lon in your point creation.

As a side note, I prefer to use the Point() method for point creation:

ptn = Point(x=latlon['lon'], y=latlon['lat'], srid=28992)

Edit due to this comment:

I tried that initializer, it seems correct to me thank you. However it doesn't seem to have solved the issue. It almost looks as the default distance unit is decameters because this works correctly. posts = Post.objects.filter(point__distance_lte=(pnt, 0.05)) this searches within a range of 5km – Evan

Since the above didn't solve your problem, I will assume that the dwithin's know problem with Distance objects apply to the distance queries as well.

As stated in the solution linked above, geometry fields default to WGS84 which have degrees as a default measurement unit.

0.05 degrees ~= 5 km, and that is why your solution worked correctly.

Maybe the geodjango team should be informed of this?

John Moutafis
  • 22,254
  • 11
  • 68
  • 112
  • I tried that initializer, it seems more correct to me thank you. However it doesnt seem to have solved the issue. It almost looks as the default distance unit is decameters because this works correctly. `posts = Post.objects.filter(point__distance_lte=(pnt, 0.05))` this searches within a range of 5km – Evan Aug 15 '17 at 19:58
  • @Evan As I see here: https://epsg.io/28992 , the default unit is meters. I have edited my answer to include a possible explanation of the issue. – John Moutafis Aug 16 '17 at 07:47
0

Same SRID ? I am using this a lot but with

source = models.PointField(geography=True, srid=4326)

and then within a manager :

def starts_within_range_of(self, my_start, distance):
    ret_value = self.filter(
        source__distance_lte=(my_start, distance))
    return ret_value

But allways with 4326

mbieren
  • 1,034
  • 8
  • 31
  • Yes the srid is the same. I kinda made it work but its not very elegant. This seems to work `posts = Post.objects.filter(point__distance_lte=(pnt, meters * 1e-05))` – Evan Jul 18 '17 at 12:05
  • did you try : `pnt = django.contrib.gis.geos.Point(x=51.8125626, y=5.8372264, srid=28992)` ? – mbieren Jul 18 '17 at 12:35
  • No i havent tried, but i dont think the problem is with the point `pnt` since i am using it in the `for` loop and it gives good distances. – Evan Jul 18 '17 at 14:52