6

I've got a django model that has a custom attribute called LocationField.

class List(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=200)
    location = LocationField(blank=True, max_length=255)

The values in this are stored as a string of format latitude, longitude. From my template, I pass a url as follows: /nearby?lat='+somevalue+'&long='+somevalue

Now, I want to return nearby entries from List depending on the values that are passed.

For this I've written a views.py function as follows:

def nearby(request):
    if request.GET['lat']:
        lat = request.GET['lat']
        longitude = request.GET['long']
        first_query = Playlist.objects.filter(location__istartswith=lat)
        for f in first_query:
           l = f.index(',')
           n_string = f[l:]

To clarify what I've done, first_query returns all entries that start with the same latitude. However, now I also want to match the longitude which is why I'm running that for loop and searching for the index of the comma that separates latitude,longitude in my LocationField. n_string takes the substring of the LocationField and I'm planning to then match it to my longitude variable.

My question is two part:

  1. How do I generate the query for matching the latitude and how do I return it to template?
  2. How do I check, in say, an area of 2 sq.km around that area?

Are there django packages for this?

Newtt
  • 6,050
  • 13
  • 68
  • 106

3 Answers3

9

There are at least 3 ways to do that:

a) Haersine distance (example in MySQL)

def nearby_spots_old(request, lat, lng, radius=5000, limit=50):
    """
    WITHOUT use of any external library, using raw MySQL and Haversine Formula
    http://en.wikipedia.org/wiki/Haversine_formula
    """
    radius = float(radius) / 1000.0

    query = """SELECT id, (6367*acos(cos(radians(%2f))
               *cos(radians(latitude))*cos(radians(longitude)-radians(%2f))
               +sin(radians(%2f))*sin(radians(latitude))))
               AS distance FROM demo_spot HAVING
               distance < %2f ORDER BY distance LIMIT 0, %d""" % (
        float(lat),
        float(lng),
        float(lat),
        radius,
        limit
    )

    queryset = Spot.objects.raw(query)
    serializer = SpotWithDistanceSerializer(queryset, many=True)

    return JSONResponse(serializer.data)

b) use of Geodjango (PostgreSQL + PostGIS)

def nearby_spots_new(request, lat, lng, radius=5000, limit=50):
    """
    WITH USE OF GEODJANGO and POSTGIS
    https://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#distance-queries
    """
    user_location = fromstr("POINT(%s %s)" % (lng, lat))
    desired_radius = {'m': radius}
    nearby_spots = Spot.objects.filter(
        mpoint__distance_lte=(user_location, D(**desired_radius))).distance(
        user_location).order_by('distance')[:limit]
    serializer = SpotWithDistanceSerializer(nearby_spots, many=True)

    return JSONResponse(serializer.data)

c) some smart queries (think about circle inscribed in square)

see here my answer: How to filter a django model with latitude and longitude coordinates that fall within a certain radius

Community
  • 1
  • 1
andilabs
  • 22,159
  • 14
  • 114
  • 151
  • Thanks a lot! The first one worked perfectly. I was using another formula that was not at all accurate! – Newtt Sep 04 '14 at 08:51
  • There could be several reasons for such inaccuracy: e.g casting issue I have bug of `%d` in query instead of `%2f`, another issue can be using constant `6367` for radius which for certain geolocation is not accurate. See here: http://www.cs.nyu.edu/visual/home/proj/tiger/gisfaq.html – andilabs Sep 04 '14 at 09:11
  • Is radius in exibit a) in meters? – wswld Sep 18 '17 at 13:51
  • @andi I don't see any m in the example. Still your solution to this problem helped me a lot, thanks. – wswld Sep 18 '17 at 13:55
  • `desired_radius = {'m': radius}` – andilabs Sep 18 '17 at 13:56
  • @andi ah, I didn't even look at the second one, I'm speaking about the first one. :) – wswld Sep 18 '17 at 14:18
1

You should use GIS-databases for storing and performing operations on coordinates, searching and so on.

For storing location use https://docs.djangoproject.com/en/dev/ref/contrib/gis/model-api/#pointfield

As database you can use https://docs.djangoproject.com/en/dev/ref/contrib/gis/install/#postgis or https://docs.djangoproject.com/en/dev/ref/contrib/gis/install/spatialite/

To search nearby you should use distance lookups, see examples at https://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#distance-lookups

coldmind
  • 5,167
  • 2
  • 22
  • 22
0

Yes, there is a package/project for this Geodjango. You can read the official documentation here.

José Ricardo Pla
  • 1,043
  • 10
  • 16