2

I want to have a radius based distance search. To do this, I want to create a buffer around a point object in order to filter objects that are inside it.

Here is where I am at with it:

>>> lat = 37.7762179974
>>> lon = -122.411562492
>>> from django.contrib.gis.geos import Point
>>> pnt = Point(lat, lon)
>>> buf = pnt.buffer(0.0001)

But I am having problems filtering the Thing objects based on whether they are inside the buffer:

>>> z = Thing.objects.filter(pnt__intersects=buf) 

(I know that the above is incorrect, but I use it to elaborate what I am trying to do.)

How can I create a buffer around the Point and then filter Things that are inside the buffer?


EDIT: models.py

class Thing(models.Model):
    lat = models.FloatField()
    lon = models.FloatField()

How can I filter based on a point comprised of a combination of these two model fields?
This cannot work obviously, because I do not have a pnt field in my model:

>>> pnt = Point(lat, lon)
>>> z = Thing.objects.filter(pnt__intersects=buf) 

But how can I do something similar?

John Moutafis
  • 22,254
  • 11
  • 68
  • 112
Nick B
  • 9,267
  • 17
  • 64
  • 105

2 Answers2

1

PostGIS has a method called ST_MakePoint which can create a 2D, 3D or 4D point.

In a previous answer we saw that it is possible to create a custom database function from an existing PostGIS function:

from django.contrib.gis.db.models.functions import GeoFunc

class MakePoint(GeoFunc):
    function='ST_MakePoint'

Now we can create a point by annotate()ing and apply the intersects on it:

z = Thing.objects.annotate(pnt=MakePoint('lat', 'lon'))
                 .filter(pnt__intersects=buf)

You can achieve the same effect by utilizing GeoFunc() and F() expressions:

from django.contrib.gis.db.models.functions import GeoFunc

z = Thing.objects.annotate(pnt=GeoFunc(
        F('lat'), F('lon'),
        function='ST_MakePoint'
    )).filter(pnt__intersects=buf)

Note: You could consider adding a pnt field in your Thing model and avoid the above.

John Moutafis
  • 22,254
  • 11
  • 68
  • 112
0

I'm not sure what you mean by "buffer", but if you want a radius based distance search you might try using the... distance!

Here is an example with a kilometer metric:

from django.contrib.gis.measure import D

Thing.objects.filter(pnt__distance_lte=(pnt,D(km=distance)))

You should certainly have a look at the docs: https://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#distance-lookups

Benjamin Toueg
  • 10,511
  • 7
  • 48
  • 79
  • Maybe my question is unclear, but I think you have missed my point (pun intended). I don't have a model field named `pnt`, only `lat` and `lon`, so I cannot filter based on `pnt`. I would just like to know a way to filter based on `lat + lon`. Thanks for any ideas! – Nick B Oct 03 '13 at 18:45
  • If there is no 'pnt' field in your model, '.filter(pnt__*)' has no sense to me. Since you are storing 'lat' and 'lon' as floats in your database, what's the point of using GeoDjango in the first place? – Benjamin Toueg Oct 03 '13 at 20:32
  • I was following the method [described in this post](https://groups.google.com/forum/#!searchin/geodjango/distance%2420search%2420geodjango%2420hekevintran/geodjango/butW7zJQhSw/4Os60LTdEywJ). Since it was written by the "lead developer of geodjango," I considered it a trustworthy source. However, I am not the authority on the topic and am willing to take additional feedback. I appreciate all of your comments up to this point! – Nick B Oct 04 '13 at 18:33
  • Your reference post dates back to Django 1.2 and the situation described in it is quite different from yours. You shouldn't have a `lat` and `lon`float fields in your model, but one and only `PointField`. – Benjamin Toueg Oct 04 '13 at 22:05