Python Monitor Water Falls(3)django restful framework
Python Monitor Water Falls(3)django restful framework
Sqlite browser to see the data
http://sqlitebrowser.org/
Set water record module
>django-admin.py startapp waterrecord
Set up the models.py to define a ORM layer to persist the data in sqlite
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
class WaterRecord(models.Model):
waterName = models.CharField('water_name', max_length=50)
released = models.BooleanField('released', default = False)
releasedDate = models.CharField('released_date', max_length=20) #2018-01-16
updateTime = models.DateTimeField('update_time', auto_now=True)
createTime = models.DateTimeField('create_time', auto_now_add=True)
def __unicode__(self):
return self.waterName + self.releasedDate
Add this to the settings.py to enable this module
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'restful_api.waterrecord',
]
Models had some changes, so
>./manage.py makemigrations
>./manage.py migrate
Check the Database Information
>python manage.py shell
>>>from restful_api.waterrecord.models import WaterRecord
>>>WaterRecord.objects.all()
<QuerySet [<WaterRecord: MableFalls2018-01-01>, <WaterRecord: MableFalls2018-01-01>, <WaterRecord: MableFalls2018-01-02>]>
Serializer to support the JSON to Python Object and Object to JSON in serializers.py
# -*- coding: utf-8 -*-
from rest_framework import serializers
from .models import WaterRecord
class WaterRecordSerializer(serializers.ModelSerializer):
class Meta:
model = WaterRecord
fields = ('id', 'waterName', 'released', 'releasedDate')
URL Mapping witch is helpful function from the framework in urls.py
# -*- coding: utf-8 -*-
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^waterrecords/$', views.water_record_list, name='water_record_list'),
# url(r'^waterrecords/$', views.WaterRecordList.as_view(), name='water_record_list'),
# url(r'^waterrecords/$', views.WaterRecordListCreate.as_view(), name='water_record_list'),
url(r'^waterrecords/(?P<pk>[0-9]+)$', views.water_record_detail, name='water_record_detail'),
]
Following the documents, I put a lot of different ways of views.py implementation there, but we only use the last 2 methods
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import generics
from .models import WaterRecord
from .serializers import WaterRecordSerializer
# APIView
class WaterRecordList(APIView):
def get(self, request, format=None):
items = WaterRecord.objects.all()
serializer = WaterRecordSerializer(items, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = WaterRecordSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# ListCreateAPIView
class WaterRecordListCreate(generics.ListCreateAPIView):
queryset = WaterRecord.objects.all()
serializer_class = WaterRecordSerializer
# api_view
@api_view(['GET', 'POST'])
def water_record_list(request):
'''
List all items or create a new item
'''
if request.method == 'GET':
items = WaterRecord.objects.all()
serializer = WaterRecordSerializer(items, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = WaterRecordSerializer(data = request.data)
if serializer.is_valid():
item = serializer.validated_data
result, created = WaterRecord.objects.get_or_create(
waterName=item['waterName'],
releasedDate=item['releasedDate'],
defaults = item)
serializerResult = WaterRecordSerializer(result)
return Response(serializerResult.data, status = status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET', 'PUT', 'DELETE'])
def water_record_detail(request, pk):
try:
item = WaterRecord.objects.get(pk=pk)
except WaterRecord.DoesNotExist:
return Response(status = status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = WaterRecordSerializer(item)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = WaterRecordSerializer(item, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
item.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Deployment
Directly run that
>python manage.py runserver
Install the deployment tool
>pip install gunicorn
Libraries, pick up one is fine.
>pip install eventlet
>pip install greenlet
>pip install gevent
It works
>gunicorn restful_api.wsgi
Setting file
>cat gunicorn.py.ini
import multiprocessing
bind = "0.0.0.0:8000"
workers = multiprocessing.cpu_count() * 2 + 1
Run the command
>gunicorn -c gunicorn.py.ini restful_api.wsgi
Command to curl the RESTful API about water record
>curl http://localhost:8000/api/waterrecords/
>curl -X POST http://localhost:8000/api/waterrecords/ -d "waterName=MableFalls&released=true&releasedDate=2018-01-01"
>curl -X DELETE http://localhost:8000/api/waterrecords/1
>curl -X PUT http://localhost:8000/api/waterrecords/2 -d "waterName=MableFalls&released=false&releasedDate=2018-01-01"
I really like to deploy in Docker as follow:
start.sh
#!/bin/sh -ex
#start the service
cd /share/water-monitor/restful_api
gunicorn -c gunicorn.py.ini restful_api.wsgi
Makefile to support the build and run
IMAGE=sillycat/public
TAG=water-monitor-restful-api
NAME=water-monitor-restful-api
docker-context:
build: docker-context
docker build -t $(IMAGE):$(TAG) .
run:
docker run -d -p 8000:8000 -v /opt/water-monitor/restful_api:/share/water-monitor/restful_api --name $(NAME) $(IMAGE):$(TAG)
debug:
docker run -ti -p 8000:8000 -v /opt/water-monitor/restful_api:/share/water-monitor/restful_api --name $(NAME) $(IMAGE):$(TAG) /bin/bash
clean:
docker stop ${NAME}
docker rm ${NAME}
logs:
docker logs ${NAME}
publish:
docker push ${IMAGE}:${TAG}
fetch:
docker pull ${IMAGE}:${TAG}
Dockerfile to adjust all the ENV
#Set up FTP in Docker
#Prepre the OS
FROM resin/raspberrypi3-python
MAINTAINER Carl Luo <luohuazju@gmail.com>
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get -y update
RUN apt-get -y dist-upgrade
#install the software
RUN pip install django
RUN pip install djangorestframework
RUN pip install markdown
RUN pip install django-filter
RUN pip install gunicorn
RUN pip install greenlet
RUN pip install gevent
RUN pip install eventlet
#start the application
EXPOSE 8000
RUN mkdir -p /app/
ADD start.sh /app/
WORKDIR /app/
CMD [ "./start.sh" ]
References:
more example
http://www.cnblogs.com/ccorz/p/djangorestframework-shi-yong-li-zi.html
http://sillycat.iteye.com/blog/2408979
Python Lover
http://sillycat.iteye.com/blog/2116834
http://sillycat.iteye.com/blog/2116836
http://sillycat.iteye.com/blog/2117212
http://sillycat.iteye.com/blog/2117576
http://sillycat.iteye.com/blog/2188140
Python Console
http://sillycat.iteye.com/blog/2372912
http://sillycat.iteye.com/blog/2373528
http://sillycat.iteye.com/blog/2373531
http://sillycat.iteye.com/blog/2373701
http://www.django-rest-framework.org/tutorial/1-serialization/
https://github.com/encode/rest-framework-tutorial
https://github.com/codingforentrepreneurs/Blog-API-with-Django-Rest-Framework
https://github.com/BurkovBA/django-rest-framework-mongoengine-example