[Fixed]-GeoDjango distance filter with distance value stored within model – query

11👍

I think you’re going to have to drop some SQL in to do what you want, as the GeoDjango helpers don’t have a way of you making a suitable Distance object that is simultaneously a Django F object (ie field lookup). You don’t say which database you’re using, but here’s how you do it with PostGIS:

Order.objects.all().extra(
    where=['ST_Distance(origin, ST_PointFromText(%s, 4326)) <= CAST(range AS double precision) / 1000'],
    params=[user.profile.geo_location.wkt]
)

Let’s explain what’s happening here, because it’s pretty thorny. Going from the left:

  • .extra() allows you to add extra fields and restrictions into a query; here we’re adding a restriction
  • ST_Distance() is the PostGIS function that the GeoDjango distance_lte operator converts into (from the Django documentation)
  • ST_PointFromText() converts from WKT syntax into a PostGIS Geometry object
  • 4326 is the default SRID for Django, but not for PostGIS so we have to specify it
  • we have to CAST your field to double precision because you’re using an integer
  • then we have to divide by 1000 to convert from metres into kilometres, which I believe is what we need
  • GeoDjango Point fields have an accessor .wkt which gives their WKT representation, which we needed earlier in our ST_PointFromText() call

Note that according to the PostGIS documentation, ST_Distance() doesn’t use indexes, so you may want to investigate using ST_DWithin() instead (it’s documented right after ST_Distance()).

Leave a comment