Django Location app Rest API

Saeed Babashahi
4 min readDec 15, 2020

In this article we will add Rest API support to previous article Add Location Point to Django, PostgreSQL app.

Photo by henry perks on Unsplash

We want to add support Rest API to our app. This feature allows other applications (like an android app or your website) connect to your app through network and utilize it. For this feature I use Django Rest Framework. DRF is a powerful framework that adds the ability of building Web APIs to your Django app.

First Install DRF by using bellow command.

pip install djangorestframework

Now add djangorestframework to INSTALLED_APPS settings.py . Then add serializers.py to your app. Now your structure looks like bellow.

App structure

Add bellow code to serializers.py .

import json

from django.contrib.gis.geos import Point
from rest_framework import serializers

from location.models import Location

class LocationSerializer(serializers.Serializer):
id = serializers.ReadOnlyField()
location = serializers.ListField(child=serializers.DecimalField(max_digits=7, decimal_places=5), max_length=2, min_length=2)

def create(self, validated_data):
validated_data['location_point'] = Point(validated_data.pop('location'))
location = Location(**validated_data)
location.save()
return location

def update(self, instance, validated_data):
if validated_data.get('location'):
instance.location_point = Point(validated_data.pop('location'))
return instance

def to_representation(self, instance):
instance.location = json.loads(instance.location_point.geojson)['coordinates']
instance = super().to_representation(instance)
return instance

In LocationSerializer class we have location and id field. Django by default adds id column to your model. It is your primary key. Location field is used for receiving and sending data through API. It’s a list containing 2 decimal fields. We will use create function on posting data to create new item in our app, update function on patch or putting data to update an existing item in our app. validated_data is data that comes through API. That data will be validated by our serializer. So we know data must be a list of two decimals. instance is the object that we want to update.

DRF can convert many different kinds of fields like string and integers. But for a location field we need to convert it by utilizing to_representation function. In this function we convert location_point to a list of two decimals.

It may come to your mind why we need a list of 2 decimals? Since a location has x and y axis which in geometry are called Latitude and longitude.

Now we must use our serializer in our view.

import json

from django.http import HttpResponse
from rest_framework import generics
from rest_framework.exceptions import ValidationError

from geoapp.models import Location
from geoapp.serializers import LocationSerializer


class CreateView(generics.CreateAPIView):
serializer_class = LocationSerializer
model = Location

def post(self, request, *args, **kwargs):
try:
serialize_data = self.get_serializer(data=request.data)
if serialize_data.is_valid(raise_exception=True):
self.perform_create(serialize_data)
return HttpResponse(
json.dumps({}),
status=201,
content_type="application/json"
)
except ValidationError as e:
return HttpResponse(
json.dumps({'message': e.detail}),
status=400,
content_type="application/json"
)


class UpdateView(generics.UpdateAPIView):
serializer_class = LocationSerializer
model = Location

def put(self, request, id, *args, **kwargs): # need full required parameters
try:
instance = self.model.objects.get(id=id)
serialize_data = self.get_serializer(instance, data=request.data)
if serialize_data.is_valid(raise_exception=True):
self.perform_update(serialize_data)
data = self.get_serializer(instance)
return HttpResponse(
json.dumps({'data': data.data}),
status=200,
content_type="application/json"
)
except self.model.DoesNotExist as d:
return HttpResponse(
json.dumps({'message': 'Instance does not exist.'}),
status=404,
content_type="application/json"
)
except ValidationError as e:
return HttpResponse(
json.dumps({'message': e.detail}),
status=400,
content_type="application/json"
)

def patch(self, request, id, *args, **kwargs): # just send parameters you want to update, don't need to send them all
try:
instance = self.model.objects.get(id=id)
permissions.check_perm_owner_update(request, instance)

serialize_data = self.get_serializer(instance, data=request.data, partial=True)
if serialize_data.is_valid(raise_exception=True):
self.perform_update(serialize_data)
data = self.get_serializer(instance)
return HttpResponse(
json.dumps({'data': data.data}),
status=200,
content_type="application/json"
)
except self.model.DoesNotExist as d:
return HttpResponse(
json.dumps({'message': 'Instance does not exist.'}),
status=404,
content_type="application/json"
)
except ValidationError as e:
return HttpResponse(
json.dumps({'message': e.detail}),
status=400,
content_type="application/json"
)


class ListView(generics.ListAPIView):
serializer_class = LocationSerializer
model = Location

def get(self, request, *args, **kwargs):
result = self.model.objects.all()
data = self.get_serializer(result, many=True)
return HttpResponse(
json.dumps({'data': data.data}),
status=200,
content_type="application/json"
)

In this code we add 3 class views for creating, updating and getting a list of items. By setting serializer_class view will connect our view to serializer and based on our instructions it will create, update or serialize data . We need to add urls to these views something like bellow.

path('create/', views.CreateView.as_view()),
path('list/', views.ListView.as_view()),
path('<int:id>/update/', views.UpdateView.as_view()),

And that was the end of coding. You can use your Rest API with postman. You can create new items by using POST http request.

Create item

Getting list of items by using GET http request.

List items

And moreover updating an instance by using PUT or PATCH http request.

update an item

Feel free to comment any problems and issues with this article, I will be glad to learn from you.

--

--

Saeed Babashahi

Backend software engineer who loves to learn. I am experienced in Python, Django, DRF, Neo4j, PostgreSQL and I am a newbie gopher :).