Django Rest Framework
一、rest api
a、api就是接口
如: - http://www.oldboyedu.com/get_user/
- http://www.oldboyedu.com/get_users/
b、api的兩個用途
1、為別人提供服務
2、前后端分離
二、restful
a、--字面意思:表征狀態轉移
b、面向資源編程,對互聯網上的任意東西都視為資源
如:- http://www.oldboyedu.com/get_user/
- http://www.oldboyedu.com/get_img/1.png
普通的API:
如:
姑娘列表: http://www.oldboyedu.com/get_girls/ http://www.oldboyedu.com/add_girl/ http://www.oldboyedu.com/del_girl/1/ http://www.oldboyedu.com/update_girl/1/
restful api:
姑娘列表: http://www.oldboyedu.com/girls/ GET: 獲取 POST: 添加 PUT: 更新 DELETE:刪除
三、restful規范
---URL
---url名詞
路徑,視網絡上任何東西都是資源,均使用名詞表示(可復數) https://api.example.com/v1/zoos https://api.example.com/v1/animals https://api.example.com/v1/employees
---status狀態碼
200 OK - [GET]:服務器成功返回用戶請求的數據,該操作是冪等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用戶新建或修改數據成功。 202 Accepted - [*]:表示一個請求已經進入后台排隊(異步任務) 204 NO CONTENT - [DELETE]:用戶刪除數據成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發出的請求有錯誤,服務器沒有進行新建或修改數據的操作,該操作是冪等的。 401 Unauthorized - [*]:表示用戶沒有權限(令牌、用戶名、密碼錯誤)。 403 Forbidden - [*] 表示用戶得到授權(與401錯誤相對),但是訪問是被禁止的。 404 NOT FOUND - [*]:用戶發出的請求針對的是不存在的記錄,服務器沒有進行操作,該操作是冪等的。 406 Not Acceptable - [GET]:用戶請求的格式不可得(比如用戶請求JSON格式,但是只有XML格式)。 410 Gone -[GET]:用戶請求的資源被永久刪除,且不會再得到的。 422 Unprocesable entity - [POST/PUT/PATCH] 當創建一個對象時,發生一個驗證錯誤。 500 INTERNAL SERVER ERROR - [*]:服務器發生錯誤,用戶將無法判斷發出的請求是否成功。 更多看這里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
---提交方式
- GET :從服務器取出資源(一項或多項)
- POST :在服務器新建一個資源
- PUT :在服務器更新資源(客戶端提供改變后的完整資源)
- PATCH :在服務器更新資源(客戶端提供改變的屬性)
- DELETE :從服務器刪除資源
---錯誤信息
狀態碼是4xx時,應返回錯誤信息,error當做key。 { error: "Invalid API key" }
---版本
URL,如:https://api.example.com/v1/ 請求頭 跨域時,引發發送多次請求
---Hypermedia link,RESTful API最好做到Hypermedia,即返回結果中提供鏈接,連向其他API方法,使得用戶不查文檔,也知道下一步應該做什么。
{"link": { "rel": "collection https://www.example.com/zoos", "href": "https://api.example.com/zoos", "title": "List of zoos", "type": "application/vnd.yourformat+json" }}
---域名
https://api.example.com 盡量將API部署在專用域名(會存在跨域問題) https://example.org/api/ API很簡單
---過濾,通過在url上傳參的形式傳遞搜索條件
https://api.example.com/v1/zoos?limit=10:指定返回記錄的數量 https://api.example.com/v1/zoos?offset=10:指定返回記錄的開始位置 https://api.example.com/v1/zoos?page=2&per_page=100:指定第幾頁,以及每頁的記錄數 https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回結果按照哪個屬性排序,以及排序順序 https://api.example.com/v1/zoos?animal_type_id=1:指定篩選條件
---返回結果,針對不同操作,服務器向用戶返回的結果應該符合以下規范
GET /collection:返回資源對象的列表(數組) GET /collection/resource:返回單個資源對象 POST /collection:返回新生成的資源對象 PUT /collection/resource:返回完整的資源對象 PATCH /collection/resource:返回完整的資源對象 DELETE /collection/resource:返回一個空文檔
- 姑娘: 方式一: http://www.oldboyedu.com/girls/ http://www.oldboyedu.com/girls/1/ GET: 獲取 POST: 添加 PUT: 更新 DELETE:刪除 方式二: http://www.oldboyedu.com/girls/ - 姑娘列表 http://www.oldboyedu.com/girl/1/ - 單獨一個
四、基於Django做API
---FBV
---CBV
路由系統:
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^users/', views.users),
url(r'^user/(\d+)', views.user),
]
FBV視圖:
from django.shortcuts import render,HttpResponse
import json
def users(request):
response = {'code':1000,'data':None}
response['data'] = [
{'name':'lg','age':19},
{'name':'mqj','age':20},
{'name':'wxp','age':5},
]
return HttpResponse(json.dumps(response),status=200)
def user(request,pk):
if request.method == "GET":
return HttpResponse(json.dumps({'name':'lg','age':19}))
elif request.method == "POST":
return HttpResponse(json.dumps({'code':1111}))
elif request.method == "PUT":
pass
elif request.method == "DELETE":
pass
CBV:
路由系統:
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^users/', views.UsersView.as_view()), url(r'^user/(\d+)', views.UserView.as_view()), 】
CBV視圖:
from django.shortcuts import render,HttpResponse from django.views import View import json class UsersView(View): def get(self,request): response = {'code': 1000, 'data': None} response['data'] = [ {'name': 'lg', 'age': 19}, {'name': 'mqj', 'age': 20}, {'name': 'wxp', 'age': 5}, ] return HttpResponse(json.dumps(response), status=200) class UserView(View): def dispatch(self, request, *args, **kwargs): # method = request.method.lower() # func = getattr(self,method) # ret = func() # return ret ret = super(UserView,self).dispatch(request,*args, **kwargs) return ret def get(self,request,pk): print(request,type(request)) return HttpResponse(json.dumps({'name': 'lg', 'age': 19})) def post(self,request,pk): return HttpResponse(json.dumps({'name': 'lg', 'age': 19})) def put(self,request,pk): return HttpResponse(json.dumps({'name': 'lg', 'age': 19})) def delete(self,request,pk): return HttpResponse(json.dumps({'name': 'lg', 'age': 19}))
五、 基於Django Rest Framework框架實現
a、安裝:pip3 install djangorestframework -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com
b、基本流程
url.py from django.conf.urls import url, include from web.views.s1_api import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
views.py
from rest_framework.views import APIView from rest_framework.response import Response class TestView(APIView): def dispatch(self, request, *args, **kwargs): """ 請求到來之后,都要執行dispatch方法,dispatch方法根據請求方式不同觸發 get/post/put等方法 注意:APIView中的dispatch方法有好多好多的功能 """ return super().dispatch(request, *args, **kwargs) def get(self, request, *args, **kwargs): return Response('GET請求,響應內容') def post(self, request, *args, **kwargs): return Response('POST請求,響應內容') def put(self, request, *args, **kwargs): return Response('PUT請求,響應內容')
c、基於Token的用戶認證
url.py:
from django.conf.urls import url from django.contrib import admin from app01 import views from app02 import views as app02_view urlpatterns = [ # django rest framework url(r'^auth/', app02_view.AuthView.as_view()), url(r'^hosts/', app02_view.HostView.as_view()), ]
views.py
from django.views import View from rest_framework.views import APIView from rest_framework.authentication import SessionAuthentication from rest_framework.authentication import BasicAuthentication from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework.exceptions import APIException from rest_framework.response import Response from app02 import models import hashlib import time # class MyBasicAuthentication(BasicAuthentication): # def authenticate_credentials(self, userid, password, request=None): # if userid == 'alex' and password == '123': # return ('alex','authaaaaaaaaaaaa') # raise APIException('認證失敗') class AuthView(APIView): authentication_classes=[] def get(self,request): """ 接收用戶名和密碼 :param request: :return: """ ret = {'code':1000,'msg':None} user = request.query_params.get('user') pwd = request.query_params.get('pwd') obj = models.UserInfo.objects.filter(username=user,password=pwd).first() if not obj: ret['code'] = 1001 ret['msg'] = "用戶名或密碼錯誤" return Response(ret) # 創建隨機字符串 ctime = time.time() key = "%s|%s" %(user,ctime) m = hashlib.md5() m.update(key.encode('utf-8')) token = m.hexdigest() # 保存到數據 obj.token = token obj.save() ret['token'] = token return Response(ret) class HostView(APIView): def get(self,request,*args,**kwargs): # 原來request對象,django.core.handlers.wsgi.WSGIRequest # 現在的request對象,rest_framework.request.Request\ self.dispatch print(request.user) print(request.auth) return Response('主機列表')
django-rest-framework - 認證 - 局部 class MyAuthentication(BaseAuthentication): def authenticate(self, request): # return None ,我不管 token = request.query_params.get('token') obj = models.UserInfo.objects.filter(token=token).first() if obj: return (obj.username,obj) raise APIException('用戶認證失敗') class AuthView(APIView): authentication_classes=[MyAuthentication,] - 全局 #配置文件 REST_FRAMEWORK = { 'UNAUTHENTICATED_USER': None, 'UNAUTHENTICATED_TOKEN': None, "DEFAULT_AUTHENTICATION_CLASSES": [ "app02.utils.MyAuthentication", ], } class HostView(APIView): def get(self,request,*args,**kwargs): # 原來request對象,django.core.handlers.wsgi.WSGIRequest # 現在的request對象,rest_framework.request.Request print(request.user) print(request.auth) return HttpResponse('主機列表')
