Spatial and Temporal Query

Eventure at the core is an engine to create and search for events. Event search API is arguably more important and frequently called than anything else on the system. The first use case that comes to mind is to search for events that are in certain proximity to a specific location. Say, you want to have a list of all events that start tomorrow in 10 miles radius from your current location.

There are two parts of this query. One part relates to time “start tomorrow” and one part relates to geographic location “in 10 miles radius from your current location”. Let us deal first with the later.

Spatial Query

This second part of the query is clearly spatial related and must be supported by a database engine that can understand and execute spatial queries. Our database engine, PostgreSQL on AWS instance, fortunately already has PostGIS (a spatial database extender that adds support for geographic objects) pre-installed. Hurray!
To incorporate PostGIS into Django project, we need to replace the database engine in settings.py with:

To query using event location, our event model needs to store latitude and longitude that are inferred from user-provided location address. This lat and long information can be stored in a PointField that we import like so:

Our event model looks like this:

Notice that we have to change the object manager to models.GeoManage().

The conversion from location address to lat and long that are stored in a Point field should be done automatically every time an insert or update is done on an Event object. Using a geocode library called geopy (pip install geopy) we can do the conversion in the model’s save function that we override:

For testing purposes, we import a geolocator of choice from geopy: from geopy.geocoders import GoogleV3. In production, lat & long should be provided by front-facing clients since server side geocoding usually has very constricted usage limitations.

Now that each Event object has lat and long stored in a Point field that can be applied spatial queries on, we just need to create a view for this. The API endpoint for this should accept 3 url parameters: lat, long and miles (distance in miles from location specified by lat, long). We override get_queryset function of the Event ListCreateAPIView class like so:

Remember to import the Distance class from gis.measure from django.contrib.gis.measure import D and initiate this Distance object with any distance in units such as miles, meters… The dwithin lookup will help to filter all saved event locations that are in a given distance to the lat, long coordinates.

Now we can send GET request to API endpoint api/events/?lat=33.679313&long=-117.907243&miles=10 to get all events that are in 10 miles radius from Costa Mesa, California, United States.

Temporal Query

The second part of the query that is time related: “start tomorrow” can easily be done using Django Rest generic filter backends. To use this, first we must install django-filter (pip install django-filter) and add this line to settings.py:

Since we want to query for all events that start after a point in time, we can create/update the Filter class as follows:

and use this class in the Event list view: filter_class = EventFilter.

At this point, we have a complete API endpoint that can do what we need api/events/?lat=33.679313&long=-117.907243&miles=10&min_start=2015-06-01 7:00:00 that will display a list of all events which locate in 10 miles radius of Costa Mesa, CA and starts after 7AM June 1st, 2015.

With the help of Django Rest backend filters, PostGIS in PostgreSQL, we was able to implement a temporal-spatial query with just a dozen lines of codes. Notice that Django backend filters can provide much more than searches on time and places. But that is for a different day. :-)

Leave a Reply

Your email address will not be published. Required fields are marked *