管理後臺-後端-Python篇
python下的開發框架挺多,Django,Tornado,Flask…,我們選用了Django來做演示是因為Django的restful框架-djangorestframework開發RestfulAPI足夠簡單成熟。目前Django的最新版本為1.9,而Django從1.7開始已經對Python的最低版本要求到2.7以上了,雖然官方推薦使用Python3,但筆者還是建議使用2.7,因為很多python下的輪子都不是很支援Python3,例如Twisted(Python的網路開發框架)也是最近才開始支援Python3。
我們先搭建基礎環境
我們建立一個Centos6.6的虛擬機器,這裡做一個小筆記,關於VisualBox如何快速克隆Centos虛擬機器:
1.複製虛擬電腦彈出框,勾選重新初始化所有網絡卡的MAC地址
2.將/etc/udev/rules.d/70-persistent-net.rules中的eth1 MAC地址覆蓋到/etc/sysconfig/network-scripts/ifcfg-eth0中的HWADDR,修改DEVICE=eth1
3.重啟網路 /etc/init.d/network restart
centos預設的python是2.6的,我們需要下載2.7原始碼覆蓋安裝
> yum install -y wget gcc sqlite-devel openssl-devel zlib-devel
> cd /tmp/
> wget https://www.python.org/ftp/python/2.7.10/Python-2.7.10.tgz
> tar -xf Python-2.7.10.tgz
> cd Python-2.7.10
> ./configure
> make
> make install
> wget https://bootstrap.pypa.io/ez_setup.py -O - | sudo /usr/local/bin/python
> easy_install django
> easy_install djangorestframework
> easy_install django-cors-headers
建立專案
> django-admin startproject RestfulProject
> cd RestfulProject
> python manage.py startapp database
將database加入到INSTALLED_APPS
# RestfulProject/settings.py
INSTALLED_APPS = (
...
"database",
...
)
資料庫建模
# database/models.py
from django.db import models
from django.utils import timezone
class News(models.Model):
title = models.CharField(max_length=100)
content = models.TextField(blank=True)
create_time = models.DateTimeField(default=timezone.now)
將News加入到django的後臺自動化管理django-admin中
# database/admin.py
from django.contrib import admin
from .models import *
admin.site.register(News)
資料庫初始化
> python manage.py makemigrations database
> python manage.py migrate
> python manage.py createsuperuser
一個Django的基礎專案即完成,我們跑起來,看看
> python manage.py runserver 0.0.0.0:8000
我們用djangorestframework來構建最簡單的CRUD
# RestfulProject/settings.py
INSTALLED_APPS = (
...
'rest_framework',
)
# RestfulProject/views.py
from rest_framework import serializers,viewsets
from database.models import News
class NewsSerializer(serializers.ModelSerializer):
class Meta:
model = News
class NewsViewSet(viewsets.ModelViewSet):
serializer_class = NewsSerializer
queryset = News.objects.all()
# RestfulProject/urls.py
...
from django.conf.urls import include
from rest_framework import routers
from RestfulProject.views import NewsViewSet
router = routers.DefaultRouter()
router.register(r'news', NewsViewSet,base_name='news')
urlpatterns = [
url(r'^', include(router.urls)),
...
]
我們可以使用postman來測試我們寫好的介面,但是djangorestframework本身集成了webapi的線上瀏覽功能,可以更方便的測試
我們來整合BasicAuth驗證功能,djangorestframework的預設驗證是使用django自帶的session驗證,我們首先來看看預設的驗證是怎樣的
# RestfulProject/views.py
from rest_framework.permissions import IsAuthenticated
class NewsViewSet(viewsets.ModelViewSet):
...
permission_classes = (IsAuthenticated,)
我們再訪問這個介面將返回403錯誤
我們來將預設認證換成BasicAuth
# RestfulProject/settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
],
}
再訪問這個介面將返回401錯誤,瀏覽器根據該錯誤將彈出認證介面
按照制定的介面文件,我們再補全一個認證介面給客戶端登入使用
# RestfulProject/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
class UserViewSet(APIView):
permission_classes = (IsAuthenticated,)
def get(self, request):
content = {
'userid':request.user.id,
'username':request.user.username,
}
return Response(content)
# RestfulProject/urls.py
from RestfulProject.views import UserViewSet
urlpatterns = [
...
url(r'^auth/info/$', UserViewSet.as_view()),
]
書寫擴充套件的協議-批量刪除
編輯RestfulProject/views.py
# RestfulProject/views.py
from rest_framework.decorators import list_route
from rest_framework import status
class NewsViewSet(viewsets.ModelViewSet):
...
@list_route(methods=['delete',])
def deletes(self, request, **kwargs):
ids = request.GET['ids'].split(',')
News.objects.filter(id__in=ids).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
書寫擴充套件協議-搜尋
# RestfulProject/views.py
class NewsViewSet(viewsets.ModelViewSet):
serializer_class = NewsSerializer
permission_classes = (IsAuthenticated,)
#queryset = News.objects.all()
def get_queryset(self):
if not 'search' in self.request.GET:
ft = News.objects.all()
else:
ft = News.objects.filter(title__contains=self.request.GET['search'])
return ft.order_by('-create_time')
書寫擴充套件協議-分頁
# RestfulProject/pagination.py
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from collections import OrderedDict
class StandardResultsSetPagination(PageNumberPagination):
page_size = 50
page_size_query_param = 'page_size'
max_page_size = 1000
def get_paginated_response(self, data):
return Response(OrderedDict([
('total_count', self.page.paginator.count),
('page_count',self.page.paginator.num_pages),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('results', data)
]))
# RestfulProject/settings.py
REST_FRAMEWORK = {
...
'DEFAULT_PAGINATION_CLASS': 'RestfulProject.pagination.StandardResultsSetPagination',
}
後端基本完成了,還剩下最後一個問題CORS,我們在本地寫一個簡單的jquery
<script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script>
<script>
$.get("http://172.17.9.177:8000/news/");
</script>
在chrome裡面除錯一下會出現如下錯誤
XMLHttpRequest cannot load http://172.17.9.177:8000/news/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 401.
我們用django-cors-headers來解決這個問題:
# RestfulProject/settings.py
INSTALLED_APPS = (
...
'corsheaders',
...
)
將cors中介軟體放置在django.middleware.common.CommonMiddleware之前
# RestfulProject/settings.py
MIDDLEWARE_CLASSES = (
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
)
設定任意網址的跨域請求都被伺服器接受
# RestfulProject/settings.py
CORS_ORIGIN_ALLOW_ALL = True
再次用jquery測試,之前那個錯誤將不再出現。