Django之Rest Framework框架

1、什麼是RESTful

  • REST與技術無關,表明的是一種軟件架構風格,REST是Representational State Transfer的簡稱,中文翻譯爲「表徵狀態轉移」
  • REST從資源的角度類審視整個網絡,它將分佈在網絡中某個節點的資源經過URL進行標識,客戶端應用經過URL來獲取資源的表徵,得到這些表徵導致這些應用轉變狀態
  • REST與技術無關,表明的是一種軟件架構風格,REST是Representational State Transfer的簡稱,中文翻譯爲「表徵狀態轉移」
  • 全部的數據,不過是經過網絡獲取的仍是操做(增刪改查)的數據,都是資源,將一切數據視爲資源是REST區別與其餘架構風格的最本質屬性
  • 對於REST這種面向資源的架構風格,有人提出一種全新的結構理念,即:面向資源架構(ROA:Resource Oriented Architecture)

2、RESTful API設計

  • API與用戶的通訊協議,老是使用HTTPs協議
  • 域名 
    • https://api.example.com                         儘可能將API部署在專用域名(會存在跨域問題)
    • https://example.org/api/                        API很簡單
  • 版本
    • URL,如:https://api.example.com/v1/
    • 請求頭                                                  跨域時,引起發送屢次請求
  • 路徑,視網絡上任何東西都是資源,均使用名詞表示(可複數)
    • https://api.example.com/v1/zoos
    • https://api.example.com/v1/animals
    • https://api.example.com/v1/employees
  • method
    • GET      :從服務器取出資源(一項或多項)
    • POST    :在服務器新建一個資源
    • PUT      :在服務器更新資源(客戶端提供改變後的完整資源)
    • PATCH  :在服務器更新資源(客戶端提供改變的屬性)
    • DELETE :從服務器刪除資源
  • 過濾,經過在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:指定篩選條件
  • 狀態碼
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
  • 錯誤處理,狀態碼是4xx時,應返回錯誤信息,error當作key。
{
    error: "Invalid API key"
}
  • 返回結果,針對不一樣操做,服務器向用戶返回的結果應該符合如下規範。
GET /collection:返回資源對象的列表(數組)
GET /collection/resource:返回單個資源對象
POST /collection:返回新生成的資源對象
PUT /collection/resource:返回完整的資源對象
PATCH /collection/resource:返回完整的資源對象
DELETE /collection/resource:返回一個空文檔
  • Hypermedia API,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"
}}

  摘自:http://www.ruanyifeng.com/blog/2014/05/restful_api.html html

3、基於Django實現

路由系統:python

urlpatterns = [
    url(r'^users', Users.as_view()),
]

CBV視圖:web

from django.views import View
from django.http import JsonResponse
 
class Users(View):
    def get(self, request, *args, **kwargs):
        result = {
            'status': True,
            'data': 'response data'
        }
        return JsonResponse(result, status=200)
 
    def post(self, request, *args, **kwargs):
        result = {
            'status': True,
            'data': 'response data'
        }
        return JsonResponse(result, status=200) 

 4、基於Django Rest Framework框架實現

4.1基本流程

url.py數據庫

from django.conf.urls import url, include
from web.views.s1_api import TestView
 
urlpatterns = [
    url(r'^test/', TestView.as_view()),
]

views.pydjango

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請求,響應內容')

上述是rest framework框架基本流程,重要的功能是在APIView的dispatch中觸發。json

4.2認證和受權

一、用戶url傳入的token認證api

url.py跨域

from django.conf.urls import url, include
from web.viewsimport TestView

urlpatterns = [
    url(r'^test/', TestView.as_view()),
]
 1 from rest_framework.views import APIView
 2 from rest_framework.response import Response
 3 from rest_framework.authentication import BaseAuthentication
 4 from rest_framework.request import Request
 5 from rest_framework import exceptions
 6 
 7 token_list = [
 8     'sfsfss123kuf3j123',
 9     'asijnfowerkkf9812',
10 ]
11 
12 
13 class TestAuthentication(BaseAuthentication):
14     def authenticate(self, request):
15         """
16         用戶認證,若是驗證成功後返回元組: (用戶,用戶Token)
17         :param request: 
18         :return: 
19             None,表示跳過該驗證;
20                 若是跳過了全部認證,默認用戶和Token和使用配置文件進行設置
21                 self._authenticator = None
22                 if api_settings.UNAUTHENTICATED_USER:
23                     self.user = api_settings.UNAUTHENTICATED_USER()
24                 else:
25                     self.user = None
26         
27                 if api_settings.UNAUTHENTICATED_TOKEN:
28                     self.auth = api_settings.UNAUTHENTICATED_TOKEN()
29                 else:
30                     self.auth = None
31             (user,token)表示驗證經過並設置用戶名和Token;
32             AuthenticationFailed異常
33         """
34         val = request.query_params.get('token')
35         if val not in token_list:
36             raise exceptions.AuthenticationFailed("用戶認證失敗")
37 
38         return ('登陸用戶', '用戶token')
39 
40     def authenticate_header(self, request):
41         """
42         Return a string to be used as the value of the `WWW-Authenticate`
43         header in a `401 Unauthenticated` response, or `None` if the
44         authentication scheme should return `403 Permission Denied` responses.
45         """
46         # 驗證失敗時,返回的響應頭WWW-Authenticate對應的值
47         pass
48 
49 
50 class TestView(APIView):
51     authentication_classes = [TestAuthentication, ]
52     permission_classes = []
53 
54     def get(self, request, *args, **kwargs):
55         print(request.user)
56         print(request.auth)
57         return Response('GET請求,響應內容')
58 
59     def post(self, request, *args, **kwargs):
60         return Response('POST請求,響應內容')
61 
62     def put(self, request, *args, **kwargs):
63         return Response('PUT請求,響應內容')
views.py

二、請求頭認證數組

1 from django.conf.urls import url, include
2 from web.viewsimport TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
url.py
 1 from rest_framework.views import APIView
 2 from rest_framework.response import Response
 3 from rest_framework.authentication import BaseAuthentication
 4 from rest_framework.request import Request
 5 from rest_framework import exceptions
 6 
 7 token_list = [
 8     'sfsfss123kuf3j123',
 9     'asijnfowerkkf9812',
10 ]
11 
12 
13 class TestAuthentication(BaseAuthentication):
14     def authenticate(self, request):
15         """
16         用戶認證,若是驗證成功後返回元組: (用戶,用戶Token)
17         :param request: 
18         :return: 
19             None,表示跳過該驗證;
20                 若是跳過了全部認證,默認用戶和Token和使用配置文件進行設置
21                 self._authenticator = None
22                 if api_settings.UNAUTHENTICATED_USER:
23                     self.user = api_settings.UNAUTHENTICATED_USER()
24                 else:
25                     self.user = None
26         
27                 if api_settings.UNAUTHENTICATED_TOKEN:
28                     self.auth = api_settings.UNAUTHENTICATED_TOKEN()
29                 else:
30                     self.auth = None
31             (user,token)表示驗證經過並設置用戶名和Token;
32             AuthenticationFailed異常
33         """
34         import base64
35         auth = request.META.get('HTTP_AUTHORIZATION', b'')
36         if auth:
37             auth = auth.encode('utf-8')
38         auth = auth.split()
39         if not auth or auth[0].lower() != b'basic':
40             raise exceptions.AuthenticationFailed('驗證失敗')
41         if len(auth) != 2:
42             raise exceptions.AuthenticationFailed('驗證失敗')
43         username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':')
44         if username == 'alex' and password == '123':
45             return ('登陸用戶', '用戶token')
46         else:
47             raise exceptions.AuthenticationFailed('用戶名或密碼錯誤')
48 
49     def authenticate_header(self, request):
50         """
51         Return a string to be used as the value of the `WWW-Authenticate`
52         header in a `401 Unauthenticated` response, or `None` if the
53         authentication scheme should return `403 Permission Denied` responses.
54         """
55         return 'Basic realm=api'
56 
57 
58 class TestView(APIView):
59     authentication_classes = [TestAuthentication, ]
60     permission_classes = []
61 
62     def get(self, request, *args, **kwargs):
63         print(request.user)
64         print(request.auth)
65         return Response('GET請求,響應內容')
66 
67     def post(self, request, *args, **kwargs):
68         return Response('POST請求,響應內容')
69 
70     def put(self, request, *args, **kwargs):
71         return Response('PUT請求,響應內容')
views.py

三、多個認證規則瀏覽器

1 from django.conf.urls import url, include
2 from web.views.s2_auth import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 from rest_framework.views import APIView
  4 from rest_framework.response import Response
  5 from rest_framework.authentication import BaseAuthentication
  6 from rest_framework.request import Request
  7 from rest_framework import exceptions
  8 
  9 token_list = [
 10     'sfsfss123kuf3j123',
 11     'asijnfowerkkf9812',
 12 ]
 13 
 14 
 15 class Test1Authentication(BaseAuthentication):
 16     def authenticate(self, request):
 17         """
 18         用戶認證,若是驗證成功後返回元組: (用戶,用戶Token)
 19         :param request: 
 20         :return: 
 21             None,表示跳過該驗證;
 22                 若是跳過了全部認證,默認用戶和Token和使用配置文件進行設置
 23                 self._authenticator = None
 24                 if api_settings.UNAUTHENTICATED_USER:
 25                     self.user = api_settings.UNAUTHENTICATED_USER() # 默認值爲:匿名用戶
 26                 else:
 27                     self.user = None
 28 
 29                 if api_settings.UNAUTHENTICATED_TOKEN:
 30                     self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默認值爲:None
 31                 else:
 32                     self.auth = None
 33             (user,token)表示驗證經過並設置用戶名和Token;
 34             AuthenticationFailed異常
 35         """
 36         import base64
 37         auth = request.META.get('HTTP_AUTHORIZATION', b'')
 38         if auth:
 39             auth = auth.encode('utf-8')
 40         else:
 41             return None
 42         print(auth,'xxxx')
 43         auth = auth.split()
 44         if not auth or auth[0].lower() != b'basic':
 45             raise exceptions.AuthenticationFailed('驗證失敗')
 46         if len(auth) != 2:
 47             raise exceptions.AuthenticationFailed('驗證失敗')
 48         username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':')
 49         if username == 'alex' and password == '123':
 50             return ('登陸用戶', '用戶token')
 51         else:
 52             raise exceptions.AuthenticationFailed('用戶名或密碼錯誤')
 53 
 54     def authenticate_header(self, request):
 55         """
 56         Return a string to be used as the value of the `WWW-Authenticate`
 57         header in a `401 Unauthenticated` response, or `None` if the
 58         authentication scheme should return `403 Permission Denied` responses.
 59         """
 60         # return 'Basic realm=api'
 61         pass
 62 
 63 class Test2Authentication(BaseAuthentication):
 64     def authenticate(self, request):
 65         """
 66         用戶認證,若是驗證成功後返回元組: (用戶,用戶Token)
 67         :param request: 
 68         :return: 
 69             None,表示跳過該驗證;
 70                 若是跳過了全部認證,默認用戶和Token和使用配置文件進行設置
 71                 self._authenticator = None
 72                 if api_settings.UNAUTHENTICATED_USER:
 73                     self.user = api_settings.UNAUTHENTICATED_USER() # 默認值爲:匿名用戶
 74                 else:
 75                     self.user = None
 76         
 77                 if api_settings.UNAUTHENTICATED_TOKEN:
 78                     self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默認值爲:None
 79                 else:
 80                     self.auth = None
 81             (user,token)表示驗證經過並設置用戶名和Token;
 82             AuthenticationFailed異常
 83         """
 84         val = request.query_params.get('token')
 85         if val not in token_list:
 86             raise exceptions.AuthenticationFailed("用戶認證失敗")
 87 
 88         return ('登陸用戶', '用戶token')
 89 
 90     def authenticate_header(self, request):
 91         """
 92         Return a string to be used as the value of the `WWW-Authenticate`
 93         header in a `401 Unauthenticated` response, or `None` if the
 94         authentication scheme should return `403 Permission Denied` responses.
 95         """
 96         pass
 97 
 98 
 99 class TestView(APIView):
100     authentication_classes = [Test1Authentication, Test2Authentication]
101     permission_classes = []
102 
103     def get(self, request, *args, **kwargs):
104         print(request.user)
105         print(request.auth)
106         return Response('GET請求,響應內容')
107 
108     def post(self, request, *args, **kwargs):
109         return Response('POST請求,響應內容')
110 
111     def put(self, request, *args, **kwargs):
112         return Response('PUT請求,響應內容')
views.py

四、認證和權限

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.authentication import BaseAuthentication
 6 from rest_framework.permissions import BasePermission
 7 
 8 from rest_framework.request import Request
 9 from rest_framework import exceptions
10 
11 token_list = [
12     'sfsfss123kuf3j123',
13     'asijnfowerkkf9812',
14 ]
15 
16 
17 class TestAuthentication(BaseAuthentication):
18     def authenticate(self, request):
19         """
20         用戶認證,若是驗證成功後返回元組: (用戶,用戶Token)
21         :param request: 
22         :return: 
23             None,表示跳過該驗證;
24                 若是跳過了全部認證,默認用戶和Token和使用配置文件進行設置
25                 self._authenticator = None
26                 if api_settings.UNAUTHENTICATED_USER:
27                     self.user = api_settings.UNAUTHENTICATED_USER() # 默認值爲:匿名用戶
28                 else:
29                     self.user = None
30         
31                 if api_settings.UNAUTHENTICATED_TOKEN:
32                     self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默認值爲:None
33                 else:
34                     self.auth = None
35             (user,token)表示驗證經過並設置用戶名和Token;
36             AuthenticationFailed異常
37         """
38         val = request.query_params.get('token')
39         if val not in token_list:
40             raise exceptions.AuthenticationFailed("用戶認證失敗")
41 
42         return ('登陸用戶', '用戶token')
43 
44     def authenticate_header(self, request):
45         """
46         Return a string to be used as the value of the `WWW-Authenticate`
47         header in a `401 Unauthenticated` response, or `None` if the
48         authentication scheme should return `403 Permission Denied` responses.
49         """
50         pass
51 
52 
53 class TestPermission(BasePermission):
54     message = "權限驗證失敗"
55 
56     def has_permission(self, request, view):
57         """
58         判斷是否有權限訪問當前請求
59         Return `True` if permission is granted, `False` otherwise.
60         :param request: 
61         :param view: 
62         :return: True有權限;False無權限
63         """
64         if request.user == "管理員":
65             return True
66 
67     # GenericAPIView中get_object時調用
68     def has_object_permission(self, request, view, obj):
69         """
70         視圖繼承GenericAPIView,並在其中使用get_object時獲取對象時,觸發單獨對象權限驗證
71         Return `True` if permission is granted, `False` otherwise.
72         :param request: 
73         :param view: 
74         :param obj: 
75         :return: True有權限;False無權限
76         """
77         if request.user == "管理員":
78             return True
79 
80 
81 class TestView(APIView):
82     # 認證的動做是由request.user觸發
83     authentication_classes = [TestAuthentication, ]
84 
85     # 權限
86     # 循環執行全部的權限
87     permission_classes = [TestPermission, ]
88 
89     def get(self, request, *args, **kwargs):
90         # self.dispatch
91         print(request.user)
92         print(request.auth)
93         return Response('GET請求,響應內容')
94 
95     def post(self, request, *args, **kwargs):
96         return Response('POST請求,響應內容')
97 
98     def put(self, request, *args, **kwargs):
99         return Response('PUT請求,響應內容')
views.py

五、全局使用

上述操做中均是對單獨視圖進行特殊配置,若是想要對全局進行配置,則須要再配置文件中寫入便可。

 1 REST_FRAMEWORK = {
 2     'UNAUTHENTICATED_USER': None,
 3     'UNAUTHENTICATED_TOKEN': None,
 4     "DEFAULT_AUTHENTICATION_CLASSES": [
 5         "web.utils.TestAuthentication",
 6     ],
 7     "DEFAULT_PERMISSION_CLASSES": [
 8         "web.utils.TestPermission",
 9     ],
10 }
settings
1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 
 6 class TestView(APIView):
 7 
 8     def get(self, request, *args, **kwargs):
 9         # self.dispatch
10         print(request.user)
11         print(request.auth)
12         return Response('GET請求,響應內容')
13 
14     def post(self, request, *args, **kwargs):
15         return Response('POST請求,響應內容')
16 
17     def put(self, request, *args, **kwargs):
18         return Response('PUT請求,響應內容')
views.py

4.3用戶訪問次數/頻率限制

一、基於用戶IP限制訪問頻率

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 import time
  4 from rest_framework.views import APIView
  5 from rest_framework.response import Response
  6 
  7 from rest_framework import exceptions
  8 from rest_framework.throttling import BaseThrottle
  9 from rest_framework.settings import api_settings
 10 
 11 # 保存訪問記錄
 12 RECORD = {
 13     '用戶IP': [12312139, 12312135, 12312133, ]
 14 }
 15 
 16 
 17 class TestThrottle(BaseThrottle):
 18     ctime = time.time
 19 
 20     def get_ident(self, request):
 21         """
 22         根據用戶IP和代理IP,當作請求者的惟一IP
 23         Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR
 24         if present and number of proxies is > 0. If not use all of
 25         HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR.
 26         """
 27         xff = request.META.get('HTTP_X_FORWARDED_FOR')
 28         remote_addr = request.META.get('REMOTE_ADDR')
 29         num_proxies = api_settings.NUM_PROXIES
 30 
 31         if num_proxies is not None:
 32             if num_proxies == 0 or xff is None:
 33                 return remote_addr
 34             addrs = xff.split(',')
 35             client_addr = addrs[-min(num_proxies, len(addrs))]
 36             return client_addr.strip()
 37 
 38         return ''.join(xff.split()) if xff else remote_addr
 39 
 40     def allow_request(self, request, view):
 41         """
 42         是否仍然在容許範圍內
 43         Return `True` if the request should be allowed, `False` otherwise.
 44         :param request: 
 45         :param view: 
 46         :return: True,表示能夠經過;False表示已超過限制,不容許訪問
 47         """
 48         # 獲取用戶惟一標識(如:IP)
 49 
 50         # 容許一分鐘訪問10次
 51         num_request = 10
 52         time_request = 60
 53 
 54         now = self.ctime()
 55         ident = self.get_ident(request)
 56         self.ident = ident
 57         if ident not in RECORD:
 58             RECORD[ident] = [now, ]
 59             return True
 60         history = RECORD[ident]
 61         while history and history[-1] <= now - time_request:
 62             history.pop()
 63         if len(history) < num_request:
 64             history.insert(0, now)
 65             return True
 66 
 67     def wait(self):
 68         """
 69         多少秒後能夠容許繼續訪問
 70         Optionally, return a recommended number of seconds to wait before
 71         the next request.
 72         """
 73         last_time = RECORD[self.ident][0]
 74         now = self.ctime()
 75         return int(60 + last_time - now)
 76 
 77 
 78 class TestView(APIView):
 79     throttle_classes = [TestThrottle, ]
 80 
 81     def get(self, request, *args, **kwargs):
 82         # self.dispatch
 83         print(request.user)
 84         print(request.auth)
 85         return Response('GET請求,響應內容')
 86 
 87     def post(self, request, *args, **kwargs):
 88         return Response('POST請求,響應內容')
 89 
 90     def put(self, request, *args, **kwargs):
 91         return Response('PUT請求,響應內容')
 92 
 93     def throttled(self, request, wait):
 94         """
 95         訪問次數被限制時,定製錯誤信息
 96         """
 97 
 98         class Throttled(exceptions.Throttled):
 99             default_detail = '請求被限制.'
100             extra_detail_singular = '請 {wait} 秒以後再重試.'
101             extra_detail_plural = '請 {wait} 秒以後再重試.'
102 
103         raise Throttled(wait)
views.py

二、基於用戶IP顯示訪問頻率(利於Django緩存)

1 REST_FRAMEWORK = {
2     'DEFAULT_THROTTLE_RATES': {
3         'test_scope': '10/m',
4     },
5 }
settings.py
1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
views.py

三、view中限制請求頻率

1 REST_FRAMEWORK = {
2     'DEFAULT_THROTTLE_RATES': {
3         'xxxxxx': '10/m',
4     },
5 }
settings.py
1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 
 6 from rest_framework import exceptions
 7 from rest_framework.throttling import ScopedRateThrottle
 8 
 9 
10 # 繼承 ScopedRateThrottle
11 class TestThrottle(ScopedRateThrottle):
12 
13     def get_cache_key(self, request, view):
14         """
15         Should return a unique cache-key which can be used for throttling.
16         Must be overridden.
17 
18         May return `None` if the request should not be throttled.
19         """
20         if not request.user:
21             ident = self.get_ident(request)
22         else:
23             ident = request.user
24 
25         return self.cache_format % {
26             'scope': self.scope,
27             'ident': ident
28         }
29 
30 
31 class TestView(APIView):
32     throttle_classes = [TestThrottle, ]
33 
34     # 在settings中獲取 xxxxxx 對應的頻率限制值
35     throttle_scope = "xxxxxx"
36 
37     def get(self, request, *args, **kwargs):
38         # self.dispatch
39         print(request.user)
40         print(request.auth)
41         return Response('GET請求,響應內容')
42 
43     def post(self, request, *args, **kwargs):
44         return Response('POST請求,響應內容')
45 
46     def put(self, request, *args, **kwargs):
47         return Response('PUT請求,響應內容')
48 
49     def throttled(self, request, wait):
50         """
51         訪問次數被限制時,定製錯誤信息
52         """
53 
54         class Throttled(exceptions.Throttled):
55             default_detail = '請求被限制.'
56             extra_detail_singular = '請 {wait} 秒以後再重試.'
57             extra_detail_plural = '請 {wait} 秒以後再重試.'
58 
59         raise Throttled(wait)
views.py

四、匿名時用IP限制+登陸時用Token限制

1 REST_FRAMEWORK = {
2     'UNAUTHENTICATED_USER': None,
3     'UNAUTHENTICATED_TOKEN': None,
4     'DEFAULT_THROTTLE_RATES': {
5         'luffy_anon': '10/m',
6         'luffy_user': '20/m',
7     },
8 }
settings.py
1 from django.conf.urls import url, include
2 from web.views.s3_throttling import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view()),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 
 6 from rest_framework.throttling import SimpleRateThrottle
 7 
 8 
 9 class LuffyAnonRateThrottle(SimpleRateThrottle):
10     """
11     匿名用戶,根據IP進行限制
12     """
13     scope = "luffy_anon"
14 
15     def get_cache_key(self, request, view):
16         # 用戶已登陸,則跳過 匿名頻率限制
17         if request.user:
18             return None
19 
20         return self.cache_format % {
21             'scope': self.scope,
22             'ident': self.get_ident(request)
23         }
24 
25 
26 class LuffyUserRateThrottle(SimpleRateThrottle):
27     """
28     登陸用戶,根據用戶token限制
29     """
30     scope = "luffy_user"
31 
32     def get_ident(self, request):
33         """
34         認證成功時:request.user是用戶對象;request.auth是token對象
35         :param request: 
36         :return: 
37         """
38         # return request.auth.token
39         return "user_token"
40 
41     def get_cache_key(self, request, view):
42         """
43         獲取緩存key
44         :param request: 
45         :param view: 
46         :return: 
47         """
48         # 未登陸用戶,則跳過 Token限制
49         if not request.user:
50             return None
51 
52         return self.cache_format % {
53             'scope': self.scope,
54             'ident': self.get_ident(request)
55         }
56 
57 
58 class TestView(APIView):
59     throttle_classes = [LuffyUserRateThrottle, LuffyAnonRateThrottle, ]
60 
61     def get(self, request, *args, **kwargs):
62         # self.dispatch
63         print(request.user)
64         print(request.auth)
65         return Response('GET請求,響應內容')
66 
67     def post(self, request, *args, **kwargs):
68         return Response('POST請求,響應內容')
69 
70     def put(self, request, *args, **kwargs):
71         return Response('PUT請求,響應內容')
views.py

五、全局使用

 1 REST_FRAMEWORK = {
 2     'DEFAULT_THROTTLE_CLASSES': [
 3         'api.utils.throttles.throttles.LuffyAnonRateThrottle',
 4         'api.utils.throttles.throttles.LuffyUserRateThrottle',
 5     ],
 6     'DEFAULT_THROTTLE_RATES': {
 7         'anon': '10/day',
 8         'user': '10/day',
 9         'luffy_anon': '10/m',
10         'luffy_user': '20/m',
11     },
12 }
settings.py

4.4版本

一、基於url的get傳參方式

如:/users?version=v1

 

1 REST_FRAMEWORK = {
2     'DEFAULT_VERSION': 'v1',            # 默認版本
3     'ALLOWED_VERSIONS': ['v1', 'v2'],   # 容許的版本
4     'VERSION_PARAM': 'version'          # URL中獲取值的key
5 }
settings

 

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view(),name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.versioning import QueryParameterVersioning
 6 
 7 
 8 class TestView(APIView):
 9     versioning_class = QueryParameterVersioning
10 
11     def get(self, request, *args, **kwargs):
12 
13         # 獲取版本
14         print(request.version)
15         # 獲取版本管理的類
16         print(request.versioning_scheme)
17 
18         # 反向生成URL
19         reverse_url = request.versioning_scheme.reverse('test', request=request)
20         print(reverse_url)
21 
22         return Response('GET請求,響應內容')
23 
24     def post(self, request, *args, **kwargs):
25         return Response('POST請求,響應內容')
26 
27     def put(self, request, *args, **kwargs):
28         return Response('PUT請求,響應內容')
view.py

 

二、基於url的正則方式

如:/v1/users/

 

1 REST_FRAMEWORK = {
2     'DEFAULT_VERSION': 'v1',            # 默認版本
3     'ALLOWED_VERSIONS': ['v1', 'v2'],   # 容許的版本
4     'VERSION_PARAM': 'version'          # URL中獲取值的key
5 }
settings.py

 

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.versioning import URLPathVersioning
 6 
 7 
 8 class TestView(APIView):
 9     versioning_class = URLPathVersioning
10 
11     def get(self, request, *args, **kwargs):
12         # 獲取版本
13         print(request.version)
14         # 獲取版本管理的類
15         print(request.versioning_scheme)
16 
17         # 反向生成URL
18         reverse_url = request.versioning_scheme.reverse('test', request=request)
19         print(reverse_url)
20 
21         return Response('GET請求,響應內容')
22 
23     def post(self, request, *args, **kwargs):
24         return Response('POST請求,響應內容')
25 
26     def put(self, request, *args, **kwargs):
27         return Response('PUT請求,響應內容')
views.py

 

 

三、基於 accept 請求頭方式

 

如:Accept: application/json; version=1.0

1 REST_FRAMEWORK = {
2     'DEFAULT_VERSION': 'v1',            # 默認版本
3     'ALLOWED_VERSIONS': ['v1', 'v2'],   # 容許的版本
4     'VERSION_PARAM': 'version'          # URL中獲取值的key
5 }
settings.py
1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.versioning import AcceptHeaderVersioning
 6 
 7 
 8 class TestView(APIView):
 9     versioning_class = AcceptHeaderVersioning
10 
11     def get(self, request, *args, **kwargs):
12         # 獲取版本 HTTP_ACCEPT頭
13         print(request.version)
14         # 獲取版本管理的類
15         print(request.versioning_scheme)
16         # 反向生成URL
17         reverse_url = request.versioning_scheme.reverse('test', request=request)
18         print(reverse_url)
19 
20         return Response('GET請求,響應內容')
21 
22     def post(self, request, *args, **kwargs):
23         return Response('POST請求,響應內容')
24 
25     def put(self, request, *args, **kwargs):
26         return Response('PUT請求,響應內容')
views.py

四、基於主機名方法

如:v1.example.com

1 ALLOWED_HOSTS = ['*']
2 REST_FRAMEWORK = {
3     'DEFAULT_VERSION': 'v1',  # 默認版本
4     'ALLOWED_VERSIONS': ['v1', 'v2'],  # 容許的版本
5     'VERSION_PARAM': 'version'  # URL中獲取值的key
6 }
settings.py
1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'^test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.versioning import HostNameVersioning
 6 
 7 
 8 class TestView(APIView):
 9     versioning_class = HostNameVersioning
10 
11     def get(self, request, *args, **kwargs):
12         # 獲取版本
13         print(request.version)
14         # 獲取版本管理的類
15         print(request.versioning_scheme)
16         # 反向生成URL
17         reverse_url = request.versioning_scheme.reverse('test', request=request)
18         print(reverse_url)
19 
20         return Response('GET請求,響應內容')
21 
22     def post(self, request, *args, **kwargs):
23         return Response('POST請求,響應內容')
24 
25     def put(self, request, *args, **kwargs):
26         return Response('PUT請求,響應內容')
views.py

五、基於django路由系統的namespace

如:example.com/v1/users/

1 REST_FRAMEWORK = {
2     'DEFAULT_VERSION': 'v1',  # 默認版本
3     'ALLOWED_VERSIONS': ['v1', 'v2'],  # 容許的版本
4     'VERSION_PARAM': 'version'  # URL中獲取值的key
5 }
settings.py
 1 from django.conf.urls import url, include
 2 from web.views import TestView
 3 
 4 urlpatterns = [
 5     url(r'^v1/', ([
 6                       url(r'test/', TestView.as_view(), name='test'),
 7                   ], None, 'v1')),
 8     url(r'^v2/', ([
 9                       url(r'test/', TestView.as_view(), name='test'),
10                   ], None, 'v2')),
11 
12 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.versioning import NamespaceVersioning
 6 
 7 
 8 class TestView(APIView):
 9     versioning_class = NamespaceVersioning
10 
11     def get(self, request, *args, **kwargs):
12         # 獲取版本
13         print(request.version)
14         # 獲取版本管理的類
15         print(request.versioning_scheme)
16         # 反向生成URL
17         reverse_url = request.versioning_scheme.reverse('test', request=request)
18         print(reverse_url)
19 
20         return Response('GET請求,響應內容')
21 
22     def post(self, request, *args, **kwargs):
23         return Response('POST請求,響應內容')
24 
25     def put(self, request, *args, **kwargs):
26         return Response('PUT請求,響應內容')
views.py

六、全局使用

1 REST_FRAMEWORK = {
2     'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
3     'DEFAULT_VERSION': 'v1',
4     'ALLOWED_VERSIONS': ['v1', 'v2'],
5     'VERSION_PARAM': 'version' 
6 }
settings.py

4.5解釋器(parser)

根據請求頭 content-type 選擇對應的解析器就請求體內容進行處理。

一、僅處理請求頭content-type爲application/json的請求體

1 from django.conf.urls import url, include
2 from web.views.s5_parser import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.request import Request
 6 from rest_framework.parsers import JSONParser
 7 
 8 
 9 class TestView(APIView):
10     parser_classes = [JSONParser, ]
11 
12     def post(self, request, *args, **kwargs):
13         print(request.content_type)
14 
15         # 獲取請求的值,並使用對應的JSONParser進行處理
16         print(request.data)
17 
18         # application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
19         print(request.POST)
20         print(request.FILES)
21 
22         return Response('POST請求,響應內容')
23 
24     def put(self, request, *args, **kwargs):
25         return Response('PUT請求,響應內容')
views.py

二、僅處理請求頭content-type爲application/x-www-form-urlencoded 的請求體

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.request import Request
 6 from rest_framework.parsers import FormParser
 7 
 8 
 9 class TestView(APIView):
10     parser_classes = [FormParser, ]
11 
12     def post(self, request, *args, **kwargs):
13         print(request.content_type)
14 
15         # 獲取請求的值,並使用對應的JSONParser進行處理
16         print(request.data)
17 
18         # application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
19         print(request.POST)
20         print(request.FILES)
21 
22         return Response('POST請求,響應內容')
23 
24     def put(self, request, *args, **kwargs):
25         return Response('PUT請求,響應內容')
views.py

三、僅處理請求頭content-type爲multipart/form-data的請求體

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.request import Request
 6 from rest_framework.parsers import MultiPartParser
 7 
 8 
 9 class TestView(APIView):
10     parser_classes = [MultiPartParser, ]
11 
12     def post(self, request, *args, **kwargs):
13         print(request.content_type)
14 
15         # 獲取請求的值,並使用對應的JSONParser進行處理
16         print(request.data)
17         # application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
18         print(request.POST)
19         print(request.FILES)
20         return Response('POST請求,響應內容')
21 
22     def put(self, request, *args, **kwargs):
23         return Response('PUT請求,響應內容')
views.py
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data">
 9     <input type="text" name="user" />
10     <input type="file" name="img">
11 
12     <input type="submit" value="提交">
13 
14 </form>
15 </body>
16 </html>
upload.py

四、僅上傳文件

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.request import Request
 6 from rest_framework.parsers import FileUploadParser
 7 
 8 
 9 class TestView(APIView):
10     parser_classes = [FileUploadParser, ]
11 
12     def post(self, request, filename, *args, **kwargs):
13         print(filename)
14         print(request.content_type)
15 
16         # 獲取請求的值,並使用對應的JSONParser進行處理
17         print(request.data)
18         # application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
19         print(request.POST)
20         print(request.FILES)
21         return Response('POST請求,響應內容')
22 
23     def put(self, request, *args, **kwargs):
24         return Response('PUT請求,響應內容')
views.py
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data">
 9     <input type="text" name="user" />
10     <input type="file" name="img">
11 
12     <input type="submit" value="提交">
13 
14 </form>
15 </body>
16 </html>
17 複製代碼
upload.py

五、同時多個Parser

當同時使用多個parser時,rest framework會根據請求頭content-type自動進行比對,並使用對應parser

1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework.request import Request
 6 from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
 7 
 8 
 9 class TestView(APIView):
10     parser_classes = [JSONParser, FormParser, MultiPartParser, ]
11 
12     def post(self, request, *args, **kwargs):
13         print(request.content_type)
14 
15         # 獲取請求的值,並使用對應的JSONParser進行處理
16         print(request.data)
17         # application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
18         print(request.POST)
19         print(request.FILES)
20         return Response('POST請求,響應內容')
21 
22     def put(self, request, *args, **kwargs):
23         return Response('PUT請求,響應內容')
views.py

六、全局使用

1 REST_FRAMEWORK = {
2     'DEFAULT_PARSER_CLASSES':[
3         'rest_framework.parsers.JSONParser'
4         'rest_framework.parsers.FormParser'
5         'rest_framework.parsers.MultiPartParser'
6     ]
7 
8 }
settings.py
1 from django.conf.urls import url, include
2 from web.views import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 from rest_framework.views import APIView
 2 from rest_framework.response import Response
 3 
 4 
 5 class TestView(APIView):
 6     def post(self, request, *args, **kwargs):
 7         print(request.content_type)
 8 
 9         # 獲取請求的值,並使用對應的JSONParser進行處理
10         print(request.data)
11         # application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
12         print(request.POST)
13         print(request.FILES)
14         return Response('POST請求,響應內容')
15 
16     def put(self, request, *args, **kwargs):
17         return Response('PUT請求,響應內容')
views.py

注意:個別特殊的值能夠經過Django的request對象 request._request 來進行獲取

4.6序列化

序列化用於對用戶請求數據進行驗證和數據進行序列化。

一、自定義字段

1 from django.conf.urls import url, include
2 from web.views.s6_serializers import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 from .. import models
 7 
 8 
 9 class PasswordValidator(object):
10     def __init__(self, base):
11         self.base = base
12 
13     def __call__(self, value):
14         if value != self.base:
15             message = 'This field must be %s.' % self.base
16             raise serializers.ValidationError(message)
17 
18     def set_context(self, serializer_field):
19         """
20         This hook is called by the serializer instance,
21         prior to the validation call being made.
22         """
23         # 執行驗證以前調用,serializer_fields是當前字段對象
24         pass
25 
26 
27 class UserSerializer(serializers.Serializer):
28     ut_title = serializers.CharField(source='ut.title')
29     user = serializers.CharField(min_length=6)
30     pwd = serializers.CharField(error_messages={'required': '密碼不能爲空'}, validators=[PasswordValidator('666')])
31 
32 
33 class TestView(APIView):
34     def get(self, request, *args, **kwargs):
35 
36         # 序列化,將數據庫查詢字段序列化爲字典
37         data_list = models.UserInfo.objects.all()
38         ser = UserSerializer(instance=data_list, many=True)
39         #
40         # obj = models.UserInfo.objects.all().first()
41         # ser = UserSerializer(instance=obj, many=False)
42         return Response(ser.data)
43 
44     def post(self, request, *args, **kwargs):
45         # 驗證,對請求發來的數據進行驗證
46         ser = UserSerializer(data=request.data)
47         if ser.is_valid():
48             print(ser.validated_data)
49         else:
50             print(ser.errors)
51 
52         return Response('POST請求,響應內容')
views.py

二、基於Model自動生成字段

1 from django.conf.urls import url, include
2 from web.views.s6_serializers import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 from .. import models
 7 
 8 
 9 class PasswordValidator(object):
10     def __init__(self, base):
11         self.base = str(base)
12 
13     def __call__(self, value):
14         if value != self.base:
15             message = 'This field must be %s.' % self.base
16             raise serializers.ValidationError(message)
17 
18     def set_context(self, serializer_field):
19         """
20         This hook is called by the serializer instance,
21         prior to the validation call being made.
22         """
23         # 執行驗證以前調用,serializer_fields是當前字段對象
24         pass
25 
26 class ModelUserSerializer(serializers.ModelSerializer):
27 
28     user = serializers.CharField(max_length=32)
29 
30     class Meta:
31         model = models.UserInfo
32         fields = "__all__"
33         # fields = ['user', 'pwd', 'ut']
34         depth = 2
35         extra_kwargs = {'user': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666), ]}}
36         # read_only_fields = ['user']
37 
38 
39 class TestView(APIView):
40     def get(self, request, *args, **kwargs):
41 
42         # 序列化,將數據庫查詢字段序列化爲字典
43         data_list = models.UserInfo.objects.all()
44         ser = ModelUserSerializer(instance=data_list, many=True)
45         #
46         # obj = models.UserInfo.objects.all().first()
47         # ser = UserSerializer(instance=obj, many=False)
48         return Response(ser.data)
49 
50     def post(self, request, *args, **kwargs):
51         # 驗證,對請求發來的數據進行驗證
52         print(request.data)
53         ser = ModelUserSerializer(data=request.data)
54         if ser.is_valid():
55             print(ser.validated_data)
56         else:
57             print(ser.errors)
58 
59         return Response('POST請求,響應內容')
views.py

三、生成URL

1 from django.conf.urls import url, include
2 from web.views.s6_serializers import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6     url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='detail'),
7 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 from .. import models
 7 
 8 
 9 class PasswordValidator(object):
10     def __init__(self, base):
11         self.base = str(base)
12 
13     def __call__(self, value):
14         if value != self.base:
15             message = 'This field must be %s.' % self.base
16             raise serializers.ValidationError(message)
17 
18     def set_context(self, serializer_field):
19         """
20         This hook is called by the serializer instance,
21         prior to the validation call being made.
22         """
23         # 執行驗證以前調用,serializer_fields是當前字段對象
24         pass
25 
26 
27 class ModelUserSerializer(serializers.ModelSerializer):
28     ut = serializers.HyperlinkedIdentityField(view_name='detail')
29     class Meta:
30         model = models.UserInfo
31         fields = "__all__"
32 
33         extra_kwargs = {
34             'user': {'min_length': 6},
35             'pwd': {'validators': [PasswordValidator(666),]},
36         }
37 
38 
39 
40 class TestView(APIView):
41     def get(self, request, *args, **kwargs):
42 
43         # 序列化,將數據庫查詢字段序列化爲字典
44         data_list = models.UserInfo.objects.all()
45         ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request})
46         #
47         # obj = models.UserInfo.objects.all().first()
48         # ser = UserSerializer(instance=obj, many=False)
49         return Response(ser.data)
50 
51     def post(self, request, *args, **kwargs):
52         # 驗證,對請求發來的數據進行驗證
53         print(request.data)
54         ser = ModelUserSerializer(data=request.data)
55         if ser.is_valid():
56             print(ser.validated_data)
57         else:
58             print(ser.errors)
59 
60         return Response('POST請求,響應內容')
views.py

四、自動生成URL

1 from django.conf.urls import url, include
2 from web.views.s6_serializers import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view(), name='test'),
6     url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='xxxx'),
7 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 from .. import models
 7 
 8 
 9 class PasswordValidator(object):
10     def __init__(self, base):
11         self.base = str(base)
12 
13     def __call__(self, value):
14         if value != self.base:
15             message = 'This field must be %s.' % self.base
16             raise serializers.ValidationError(message)
17 
18     def set_context(self, serializer_field):
19         """
20         This hook is called by the serializer instance,
21         prior to the validation call being made.
22         """
23         # 執行驗證以前調用,serializer_fields是當前字段對象
24         pass
25 
26 
27 class ModelUserSerializer(serializers.HyperlinkedModelSerializer):
28     ll = serializers.HyperlinkedIdentityField(view_name='xxxx')
29     tt = serializers.CharField(required=False)
30 
31     class Meta:
32         model = models.UserInfo
33         fields = "__all__"
34         list_serializer_class = serializers.ListSerializer
35 
36         extra_kwargs = {
37             'user': {'min_length': 6},
38             'pwd': {'validators': [PasswordValidator(666), ]},
39             'url': {'view_name': 'xxxx'},
40             'ut': {'view_name': 'xxxx'},
41         }
42 
43 
44 class TestView(APIView):
45     def get(self, request, *args, **kwargs):
46         # # 序列化,將數據庫查詢字段序列化爲字典
47         data_list = models.UserInfo.objects.all()
48         ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request})
49         # # 若是Many=True
50         # # 或
51         # # obj = models.UserInfo.objects.all().first()
52         # # ser = UserSerializer(instance=obj, many=False)
53         return Response(ser.data)
54 
55     def post(self, request, *args, **kwargs):
56         # 驗證,對請求發來的數據進行驗證
57         print(request.data)
58         ser = ModelUserSerializer(data=request.data)
59         if ser.is_valid():
60             print(ser.validated_data)
61         else:
62             print(ser.errors)
63 
64         return Response('POST請求,響應內容')
views.py

4.7分頁

一、根據頁碼進行分頁

1 from django.conf.urls import url, include
2 from rest_framework import routers
3 from web.views import s9_pagination
4 
5 urlpatterns = [
6     url(r'^test/', s9_pagination.UserViewSet.as_view()),
7 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework import serializers
 5 from .. import models
 6 
 7 from rest_framework.pagination import PageNumberPagination
 8 
 9 
10 class StandardResultsSetPagination(PageNumberPagination):
11     # 默認每頁顯示的數據條數
12     page_size = 1
13     # 獲取URL參數中設置的每頁顯示數據條數
14     page_size_query_param = 'page_size'
15 
16     # 獲取URL參數中傳入的頁碼key
17     page_query_param = 'page'
18 
19     # 最大支持的每頁顯示的數據條數
20     max_page_size = 1
21 
22 
23 class UserSerializer(serializers.ModelSerializer):
24     class Meta:
25         model = models.UserInfo
26         fields = "__all__"
27 
28 
29 class UserViewSet(APIView):
30     def get(self, request, *args, **kwargs):
31         user_list = models.UserInfo.objects.all().order_by('-id')
32 
33         # 實例化分頁對象,獲取數據庫中的分頁數據
34         paginator = StandardResultsSetPagination()
35         page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)
36 
37         # 序列化對象
38         serializer = UserSerializer(page_user_list, many=True)
39 
40         # 生成分頁和數據
41         response = paginator.get_paginated_response(serializer.data)
42         return response
views.py

二、位置和個數進行分頁

1 from django.conf.urls import url, include
2 from web.views import s9_pagination
3 
4 urlpatterns = [
5     url(r'^test/', s9_pagination.UserViewSet.as_view()),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework import serializers
 5 from .. import models
 6 
 7 from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
 8 
 9 
10 class StandardResultsSetPagination(LimitOffsetPagination):
11     # 默認每頁顯示的數據條數
12     default_limit = 10
13     # URL中傳入的顯示數據條數的參數
14     limit_query_param = 'limit'
15     # URL中傳入的數據位置的參數
16     offset_query_param = 'offset'
17     # 最大每頁顯得條數
18     max_limit = None
19 
20 class UserSerializer(serializers.ModelSerializer):
21     class Meta:
22         model = models.UserInfo
23         fields = "__all__"
24 
25 
26 class UserViewSet(APIView):
27     def get(self, request, *args, **kwargs):
28         user_list = models.UserInfo.objects.all().order_by('-id')
29 
30         # 實例化分頁對象,獲取數據庫中的分頁數據
31         paginator = StandardResultsSetPagination()
32         page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)
33 
34         # 序列化對象
35         serializer = UserSerializer(page_user_list, many=True)
36 
37         # 生成分頁和數據
38         response = paginator.get_paginated_response(serializer.data)
39         return response
views.py

三、遊標分頁

1 from django.conf.urls import url, include
2 from web.views import s9_pagination
3 
4 urlpatterns = [
5     url(r'^test/', s9_pagination.UserViewSet.as_view()),
6 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework import serializers
 5 from .. import models
 6 
 7 from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
 8 
 9 
10 class StandardResultsSetPagination(CursorPagination):
11     # URL傳入的遊標參數
12     cursor_query_param = 'cursor'
13     # 默認每頁顯示的數據條數
14     page_size = 2
15     # URL傳入的每頁顯示條數的參數
16     page_size_query_param = 'page_size'
17     # 每頁顯示數據最大條數
18     max_page_size = 1000
19 
20     # 根據ID從大到小排列
21     ordering = "id"
22 
23 
24 
25 class UserSerializer(serializers.ModelSerializer):
26     class Meta:
27         model = models.UserInfo
28         fields = "__all__"
29 
30 
31 class UserViewSet(APIView):
32     def get(self, request, *args, **kwargs):
33         user_list = models.UserInfo.objects.all().order_by('-id')
34 
35         # 實例化分頁對象,獲取數據庫中的分頁數據
36         paginator = StandardResultsSetPagination()
37         page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)
38 
39         # 序列化對象
40         serializer = UserSerializer(page_user_list, many=True)
41 
42         # 生成分頁和數據
43         response = paginator.get_paginated_response(serializer.data)
44         return response
views.py

4.8路由系統

一、自定義路由

1 from django.conf.urls import url, include
2 from web.views import s11_render
3 
4 urlpatterns = [
5     url(r'^test/$', s11_render.TestView.as_view()),
6     url(r'^test\.(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view()),
7     url(r'^test/(?P<pk>[^/.]+)/$', s11_render.TestView.as_view()),
8     url(r'^test/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view())
9 ]
urls.py
 1 from rest_framework.views import APIView
 2 from rest_framework.response import Response
 3 from .. import models
 4 
 5 
 6 class TestView(APIView):
 7     def get(self, request, *args, **kwargs):
 8         print(kwargs)
 9         print(self.renderer_classes)
10         return Response('...')
views.py

二、半自動路由

1 from django.conf.urls import url, include
2 from web.views import s10_generic
3 
4 urlpatterns = [
5     url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
6     url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view(
7         {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
8 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.viewsets import ModelViewSet
 4 from rest_framework import serializers
 5 from .. import models
 6 
 7 
 8 class UserSerializer(serializers.ModelSerializer):
 9     class Meta:
10         model = models.UserInfo
11         fields = "__all__"
12 
13 
14 class UserViewSet(ModelViewSet):
15     queryset = models.UserInfo.objects.all()
16     serializer_class = UserSerializer
views.py

三、全自動路由

 1 from django.conf.urls import url, include
 2 from rest_framework import routers
 3 from web.views import s10_generic
 4 
 5 
 6 router = routers.DefaultRouter()
 7 router.register(r'users', s10_generic.UserViewSet)
 8 
 9 urlpatterns = [
10     url(r'^', include(router.urls)),
11 ]
urls.py
 1 from rest_framework.viewsets import ModelViewSet
 2 from rest_framework import serializers
 3 from .. import models
 4 
 5 
 6 class UserSerializer(serializers.ModelSerializer):
 7     class Meta:
 8         model = models.UserInfo
 9         fields = "__all__"
10 
11 
12 class UserViewSet(ModelViewSet):
13     queryset = models.UserInfo.objects.all()
14     serializer_class = UserSerializer
views.py

 

4.9視圖

一、GenericViewSet

1 from django.conf.urls import url, include
2 from web.views.s7_viewset import TestView
3 
4 urlpatterns = [
5     url(r'test/', TestView.as_view({'get':'list'}), name='test'),
6     url(r'detail/(?P<pk>\d+)/', TestView.as_view({'get':'list'}), name='xxxx'),
7 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework import viewsets
 4 from rest_framework.response import Response
 5 
 6 
 7 class TestView(viewsets.GenericViewSet):
 8     def list(self, request, *args, **kwargs):
 9         return Response('...')
10 
11     def add(self, request, *args, **kwargs):
12         pass
13 
14     def delete(self, request, *args, **kwargs):
15         pass
16 
17     def edit(self, request, *args, **kwargs):
18         pass
views.py

二、ModelViewSet(自定義URL)

1 from django.conf.urls import url, include
2 from web.views import s10_generic
3 
4 urlpatterns = [
5     url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
6     url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view(
7         {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
8 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.viewsets import ModelViewSet
 4 from rest_framework import serializers
 5 from .. import models
 6 
 7 
 8 class UserSerializer(serializers.ModelSerializer):
 9     class Meta:
10         model = models.UserInfo
11         fields = "__all__"
12 
13 
14 class UserViewSet(ModelViewSet):
15     queryset = models.UserInfo.objects.all()
16     serializer_class = UserSerializer
views.py

三、ModelViewSet(rest framework路由)

 1 from django.conf.urls import url, include
 2 from rest_framework import routers
 3 from app01 import views
 4 
 5 router = routers.DefaultRouter()
 6 router.register(r'users', views.UserViewSet)
 7 router.register(r'groups', views.GroupViewSet)
 8 
 9 # Wire up our API using automatic URL routing.
10 # Additionally, we include login URLs for the browsable API.
11 urlpatterns = [
12     url(r'^', include(router.urls)),
13 ]
urls.py
 1 from rest_framework import viewsets
 2 from rest_framework import serializers
 3 
 4 
 5 class UserSerializer(serializers.HyperlinkedModelSerializer):
 6     class Meta:
 7         model = models.User
 8         fields = ('url', 'username', 'email', 'groups')
 9 
10 
11 class GroupSerializer(serializers.HyperlinkedModelSerializer):
12     class Meta:
13         model = models.Group
14         fields = ('url', 'name')
15         
16 class UserViewSet(viewsets.ModelViewSet):
17     """
18     API endpoint that allows users to be viewed or edited.
19     """
20     queryset = User.objects.all().order_by('-date_joined')
21     serializer_class = UserSerializer
22 
23 
24 class GroupViewSet(viewsets.ModelViewSet):
25     """
26     API endpoint that allows groups to be viewed or edited.
27     """
28     queryset = Group.objects.all()
29     serializer_class = GroupSerializer
views.py

4.10渲染器

根據 用戶請求URL 或 用戶可接受的類型,篩選出合適的 渲染組件。
用戶請求URL:

  • http://127.0.0.1:8000/test/?format=json
  • http://127.0.0.1:8000/test.json

用戶請求頭:

  • Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

一、json

訪問URL:

    • http://127.0.0.1:8000/test/?format=json
    • http://127.0.0.1:8000/test.json
    • http://127.0.0.1:8000/test/ 
1 from django.conf.urls import url, include
2 from web.views import s11_render
3 
4 urlpatterns = [
5     url(r'^test/$', s11_render.TestView.as_view()),
6     url(r'^test\.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()),
7 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 
 7 from rest_framework.renderers import JSONRenderer
 8 
 9 from .. import models
10 
11 
12 class TestSerializer(serializers.ModelSerializer):
13     class Meta:
14         model = models.UserInfo
15         fields = "__all__"
16 
17 
18 class TestView(APIView):
19     renderer_classes = [JSONRenderer, ]
20 
21     def get(self, request, *args, **kwargs):
22         user_list = models.UserInfo.objects.all()
23         ser = TestSerializer(instance=user_list, many=True)
24         return Response(ser.data)
views.py

二、 表格

訪問URL:

  • http://127.0.0.1:8000/test/?format=admin
  • http://127.0.0.1:8000/test.admin
  • http://127.0.0.1:8000/test/ 
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 
 7 from rest_framework.renderers import AdminRenderer
 8 
 9 from .. import models
10 
11 
12 class TestSerializer(serializers.ModelSerializer):
13     class Meta:
14         model = models.UserInfo
15         fields = "__all__"
16 
17 
18 class TestView(APIView):
19     renderer_classes = [AdminRenderer, ]
20 
21     def get(self, request, *args, **kwargs):
22         user_list = models.UserInfo.objects.all()
23         ser = TestSerializer(instance=user_list, many=True)
24         return Response(ser.data)
views.py

三、 Form表單

訪問URL:

  • http://127.0.0.1:8000/test/?format=form
  • http://127.0.0.1:8000/test.form
  • http://127.0.0.1:8000/test/ 
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 
 7 from rest_framework.renderers import JSONRenderer
 8 from rest_framework.renderers import AdminRenderer
 9 from rest_framework.renderers import HTMLFormRenderer
10 
11 from .. import models
12 
13 
14 class TestSerializer(serializers.ModelSerializer):
15     class Meta:
16         model = models.UserInfo
17         fields = "__all__"
18 
19 
20 class TestView(APIView):
21     renderer_classes = [HTMLFormRenderer, ]
22 
23     def get(self, request, *args, **kwargs):
24         user_list = models.UserInfo.objects.all().first()
25         ser = TestSerializer(instance=user_list, many=False)
26         return Response(ser.data)
views.py

四、自定義顯示模板

訪問URL:

  • http://127.0.0.1:8000/test/?format=html
  • http://127.0.0.1:8000/test.html
  • http://127.0.0.1:8000/test/ 
1 from django.conf.urls import url, include
2 from web.views import s11_render
3 
4 urlpatterns = [
5     url(r'^test/$', s11_render.TestView.as_view()),
6     url(r'^test\.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()),
7 ]
urls.py
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 from rest_framework.renderers import TemplateHTMLRenderer
 7 
 8 from .. import models
 9 
10 
11 class TestSerializer(serializers.ModelSerializer):
12     class Meta:
13         model = models.UserInfo
14         fields = "__all__"
15 
16 
17 class TestView(APIView):
18     renderer_classes = [TemplateHTMLRenderer, ]
19 
20     def get(self, request, *args, **kwargs):
21         user_list = models.UserInfo.objects.all().first()
22         ser = TestSerializer(instance=user_list, many=False)
23         return Response(ser.data, template_name='user_detail.html')
views.py
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     {{ user }}
 9     {{ pwd }}
10     {{ ut }}
11 </body>
12 </html>
userdetail.html

 

五、 瀏覽器格式API+JSON

訪問URL:

  • http://127.0.0.1:8000/test/?format=api
  • http://127.0.0.1:8000/test.api
  • http://127.0.0.1:8000/test/ 
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 from rest_framework.views import APIView
 4 from rest_framework.response import Response
 5 from rest_framework import serializers
 6 
 7 from rest_framework.renderers import JSONRenderer
 8 from rest_framework.renderers import BrowsableAPIRenderer
 9 
10 from .. import models
11 
12 
13 class TestSerializer(serializers.ModelSerializer):
14     class Meta:
15         model = models.UserInfo
16         fields = "__all__"
17 
18 
19 class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):
20     def get_default_renderer(self, view):
21         return JSONRenderer()
22 
23 
24 class TestView(APIView):
25     renderer_classes = [CustomBrowsableAPIRenderer, ]
26 
27     def get(self, request, *args, **kwargs):
28         user_list = models.UserInfo.objects.all().first()
29         ser = TestSerializer(instance=user_list, many=False)
30         return Response(ser.data, template_name='user_detail.html')
View Code

 

注意:若是同時多個存在時,自動根據URL後綴來選擇渲染器。

相關文章
相關標籤/搜索