How to Create a Django Rest Framework-GIS on Ubuntu 16.04 Server (Part 2)

Prerequisites

You must have completed the steps in Part 1.

Step 1: Create Django Models

A model is the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you’re storing. Generally, each model maps to a single database table.

$ sudo nano geoapi/geoapi/settings.pyINSTALLED_APPS = [
# ...
'mygeoapi',
]
$ sudo nano geoapi/mygeoapi/models.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
from django.contrib.gis.db import models
from django.contrib.postgres.fields import HStoreField
class School(models.Model):
name = models.CharField(max_length=100)
county = models.CharField(max_length=100, null=True)
enrollment = models.IntegerField()
location = models.PointField(srid=4326)
electricity_availability = models.BooleanField(default=False)
emmis_code = models.IntegerField(null=False,default=0)
def __unicode__(self):
return self.name
class Link(models.Model):
"""
Metadata is stored in a PostgreSQL HStore field, which allows us to
store arbitrary key-value pairs with a link record.
"""
metadata = HStoreField(blank=True, null=True, default=dict)
geo = models.LineStringField()
objects = models.GeoManager()
  1. Name — the name of the school
  2. County — county name of school
  3. Enrollment — number of learners
  4. Emmis code — school unique code
  5. Electricity Availability
  6. Exact location — point(x,y)
$ sudo -u postgres psql -d geoapigeoapi=# create extension hstore;
$ geoapi/manage.py migrate

Step 2: Serializing Django Objects

GeoFeatureModelSerializer is a subclass of rest_framework.ModelSerializer which will output data in a format that is GeoJSON compatible.GeoJSON is file format for representing geodata as JSON. Serializing an object list GeoFeatureModelSerializer will create a FeatureCollection.GeoFeatureModelSerializer requires you to define a geo_field to be serialized as the “geometry”.

$ nano geoapi/mygeoapi/serializers.py
from rest_framework import serializers
from django.contrib.auth.models import User, Group
from mygeoapi.models import School
from rest_framework_gis.serializers import GeoFeatureModelSerializer
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('username', 'id', 'email', 'groups')
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Group
fields = ('id', 'name')
class SchoolSerializer(GeoFeatureModelSerializer):
""" A class to serialize locations as GeoJSON compatible data """
class Meta:
model = School
geo_field = 'location'
auto_bbox = True
# you can also explicitly declare which fields you want to include
# as with a ModelSerializer.
fields = ('id', 'name', 'county', 'enrollment', 'location', 'electricity_availability', 'emmis_code')

Step 3: Creating Views

A view is a callable which takes a request and returns a response.We will be using @api_view wrapper to write API function based views.These wrapper provide a few bits of functionality such as making sure you receive Request instances in your view, and adding context to Response objects so that content negotiation can be performed.

$ sudo nano geoapi/mygeoapi/views.py
from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from .serializers import UserSerializer, GroupSerializer, SchoolSerializer
from .models import School
from rest_framework_gis.filters import DistanceToPointFilter
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['GET'])
def api_root(request, format=None):
return Response({
'users': reverse('user-list', request=request, format=format),
'groups': reverse('group-list', request=request, format=format),
'schools': reverse('schools-list', request=request, format=format),
})
  • Organization of code related to specific HTTP methods (GET, POST, etc.) can be addressed by separate methods instead of conditional branching.
  • Object oriented techniques such as mixins (multiple inheritance) can be used to factor code into reusable components.
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all().order_by('date_joined')
serializer_class = UserSerializer
class GroupViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows group to be viewed or edited.
"""
queryset=Group.objects.all()
serializer_class=GroupSerializer
class SchoolViewSet(viewsets.ModelViewSet):
queryset = School.objects.all()
serializer_class = SchoolSerializer
distance_filter_field = 'geometry'
filter_backends = (DistanceToPointFilter,)
bbox_filter_include_overlapping = True
$ pip install django-filter

Step 4: Create URLs

Finally we need to wire these views up. Create the mygeoapi/urls.py file and add the following:

$ nano geoapi/mygeoapi/urls.pyfrom django.conf.urls import url, include
from .views import UserViewSet, GroupViewSet, SchoolViewSet, api_root
from rest_framework.urlpatterns import format_suffix_patterns
user_list = UserViewSet.as_view({
'get': 'list'
})
user_detail = UserViewSet.as_view({
'get': 'retrieve',
'post': 'create',
'put': 'update',
'delete': 'destroy'
})
group_list = GroupViewSet.as_view({
'get': 'list'
})
group_detail = GroupViewSet.as_view({
'get': 'retrieve',
'post': 'create',
'put': 'update',
'delete': 'destroy'
})
school_list = SchoolViewSet.as_view({
'get': 'list'
})
school_detail = SchoolViewSet.as_view({
'get': 'retrieve',
'post': 'create',
'put': 'update',
'delete': 'destroy'
})
urlpatterns = [
url(r'^$', api_root),
url(r'^users', user_list, name=user_list),
url(r'^user/(?P<pk>[0-9]+)/$', user_detail, name=user_detail),
url(r'^groups', user_list, name=group_list),
url(r'^groups/(?P<pk>[0-9]+)/$', user_detail, name=group_detail),
url(r'^schools', school_list, name=school_list),
url(r'^schools/(?P<pk>[0-9]+)/$', school_detail, name=school_detail),
] # Login and logout views for the browsable API
urlpatterns += [
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
]
from django.conf.urls import url, include
from django.contrib import admin
from mygeoapi import views
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)
router.register(r'schools', views.SchoolViewSet)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^', include(router.urls))
]

Step 5: Make the mygeoapi App Modifiable in the Admin

Just one thing to do: we need to tell the admin that School objects have an admin interface. To do this, open the mygeoapi/admin.py file, and edit it to look like this:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib import admin
from .models import School
admin.site.register(School)

Step 6: Restart the Development Server

Let’s make sure that our app is functioning well. Run the following command to check our progress then open the development server in your browser and you will see a congratulations message.:

$ geoapi/manage.py runserver 0.0.0.0:8000
http://server_domain_or_IP:8000
  1. users
  2. groups
  3. schools

Conclusion

We are now able to create a Django Rest Framework that is GIS enabled. You can find and clone the source code on my GitHub.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alibaba Cloud

Alibaba Cloud

Follow me to keep abreast with the latest technology news, industry insights, and developer trends. Alibaba Cloud website:https://www.alibabacloud.com