Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning nearby locations in Django

Tags:

python

django

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?

like image 987
Newtt Avatar asked Sep 02 '14 12:09

Newtt


2 Answers

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

like image 174
andilabs Avatar answered Sep 24 '22 19:09

andilabs


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

like image 27
coldmind Avatar answered Sep 23 '22 19:09

coldmind