官網鏈接:http://www.django-rest-framework.org/
一、概念:什么是rest framework
rest 是representational state transfer的縮寫,意為‘表征狀態轉移’
REST從資源的角度類審視整個網絡,它將分布在網絡中某個節點的資源通過URL進行標識,客戶端應用通過URL來獲取資源的表征,獲得這些表征致使這些應用轉變狀態。
所以 django rest framework 又可稱為‘面向資源編程’
二、Restful API設計
1、API與用戶的通信協議,總是使用HTTPs協議。
2、域名
https://api.example.com #盡量將API 部署在專用域名(會存在跨域問題)
3、版本
https://api.example.com/v1/ ##在URL后面添加上版本
4、路徑
https://api.example.com/v1/Humans
https://api.example.com/v1/Chinese
##路徑命名要使用名詞(可復數)
5、請求方法(method):
GET :從服務器取出資源(一項或多項)
POST :在服務器新建一個資源
PUT :在服務器更新資源(客戶端提供改變后的完整資源)
PATCH :在服務器更新資源(客戶端提供改變的屬性)
DELETE :從服務器刪除資源
6、狀態碼
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
Rest framework 在django源碼中的執行流程
執行流程
urls.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請求,響應內容')
對django的request進行加工,形成新的request
Django Rest Framework 框架實現
1、基本流程
urls.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請求,響應內容')
總結:
請求到達后,首先在APIView的 dispatch方法觸發。
2、認證和授權:
a 用戶URL傳入的token認證:
urls.py
from django.conf.urls import url, include
from web.viewsimport TestView
urlpatterns = [
url(r'^test/', TestView.as_view()),
]
urls.py
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptions
token_list = [
'sfsfss123kuf3j123',
'asijnfowerkkf9812',
]
class TestAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
用戶認證,如果驗證成功后返回元組: (用戶,用戶Token)
:param request:
:return:
None,表示跳過該驗證;
如果跳過了所有認證,默認用戶和Token和使用配置文件進行設置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER()
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()
else:
self.auth = None
(user,token)表示驗證通過并設置用戶名和Token;
AuthenticationFailed異常
"""
val = request.query_params.get('token')
if val not in token_list:
raise exceptions.AuthenticationFailed("用戶認證失敗")
return ('登錄用戶', '用戶token')
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
# 驗證失敗時,返回的響應頭WWW-Authenticate對應的值
pass
class TestView(APIView):
authentication_classes = [TestAuthentication, ]
permission_classes = []
def get(self, request, *args, **kwargs):
print(request.user)
print(request.auth)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
b、請求頭認證
from django.conf.urls import url, include
from web.viewsimport TestView
urlpatterns = [
url(r'^test/', TestView.as_view()),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptions
token_list = [
'sfsfss123kuf3j123',
'asijnfowerkkf9812',
]
class TestAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
用戶認證,如果驗證成功后返回元組: (用戶,用戶Token)
:param request:
:return:
None,表示跳過該驗證;
如果跳過了所有認證,默認用戶和Token和使用配置文件進行設置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER()
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()
else:
self.auth = None
(user,token)表示驗證通過并設置用戶名和Token;
AuthenticationFailed異常
"""
import base64
auth = request.META.get('HTTP_AUTHORIZATION', b'')
if auth:
auth = auth.encode('utf-8')
auth = auth.split()
if not auth or auth[0].lower() != b'basic':
raise exceptions.AuthenticationFailed('驗證失敗')
if len(auth) != 2:
raise exceptions.AuthenticationFailed('驗證失敗')
username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':')
if username == 'alex' and password == '123':
return ('登錄用戶', '用戶token')
else:
raise exceptions.AuthenticationFailed('用戶名或密碼錯誤')
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
return 'Basic realm=api'
class TestView(APIView):
authentication_classes = [TestAuthentication, ]
permission_classes = []
def get(self, request, *args, **kwargs):
print(request.user)
print(request.auth)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
c. 多個認證規則
urls.py
from django.conf.urls import url, include
from web.views.s2_auth import TestView
urlpatterns = [
url(r'^test/', TestView.as_view()),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.request import Request
from rest_framework import exceptions
token_list = [
'sfsfss123kuf3j123',
'asijnfowerkkf9812',
]
class Test1Authentication(BaseAuthentication):
def authenticate(self, request):
"""
用戶認證,如果驗證成功后返回元組: (用戶,用戶Token)
:param request:
:return:
None,表示跳過該驗證;
如果跳過了所有認證,默認用戶和Token和使用配置文件進行設置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER() # 默認值為:匿名用戶
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默認值為:None
else:
self.auth = None
(user,token)表示驗證通過并設置用戶名和Token;
AuthenticationFailed異常
"""
import base64
auth = request.META.get('HTTP_AUTHORIZATION', b'')
if auth:
auth = auth.encode('utf-8')
else:
return None
print(auth,'xxxx')
auth = auth.split()
if not auth or auth[0].lower() != b'basic':
raise exceptions.AuthenticationFailed('驗證失敗')
if len(auth) != 2:
raise exceptions.AuthenticationFailed('驗證失敗')
username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':')
if username == 'alex' and password == '123':
return ('登錄用戶', '用戶token')
else:
raise exceptions.AuthenticationFailed('用戶名或密碼錯誤')
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
# return 'Basic realm=api'
pass
class Test2Authentication(BaseAuthentication):
def authenticate(self, request):
"""
用戶認證,如果驗證成功后返回元組: (用戶,用戶Token)
:param request:
:return:
None,表示跳過該驗證;
如果跳過了所有認證,默認用戶和Token和使用配置文件進行設置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER() # 默認值為:匿名用戶
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默認值為:None
else:
self.auth = None
(user,token)表示驗證通過并設置用戶名和Token;
AuthenticationFailed異常
"""
val = request.query_params.get('token')
if val not in token_list:
raise exceptions.AuthenticationFailed("用戶認證失敗")
return ('登錄用戶', '用戶token')
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
pass
class TestView(APIView):
authentication_classes = [Test1Authentication, Test2Authentication]
permission_classes = []
def get(self, request, *args, **kwargs):
print(request.user)
print(request.auth)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
d. 認證和權限
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view()),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermission
from rest_framework.request import Request
from rest_framework import exceptions
token_list = [
'sfsfss123kuf3j123',
'asijnfowerkkf9812',
]
class TestAuthentication(BaseAuthentication):
def authenticate(self, request):
"""
用戶認證,如果驗證成功后返回元組: (用戶,用戶Token)
:param request:
:return:
None,表示跳過該驗證;
如果跳過了所有認證,默認用戶和Token和使用配置文件進行設置
self._authenticator = None
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER() # 默認值為:匿名用戶
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默認值為:None
else:
self.auth = None
(user,token)表示驗證通過并設置用戶名和Token;
AuthenticationFailed異常
"""
val = request.query_params.get('token')
if val not in token_list:
raise exceptions.AuthenticationFailed("用戶認證失敗")
return ('登錄用戶', '用戶token')
def authenticate_header(self, request):
"""
Return a string to be used as the value of the `WWW-Authenticate`
header in a `401 Unauthenticated` response, or `None` if the
authentication scheme should return `403 Permission Denied` responses.
"""
pass
class TestPermission(BasePermission):
message = "權限驗證失敗"
def has_permission(self, request, view):
"""
判斷是否有權限訪問當前請求
Return `True` if permission is granted, `False` otherwise.
:param request:
:param view:
:return: True有權限;False無權限
"""
if request.user == "管理員":
return True
# GenericAPIView中get_object時調用
def has_object_permission(self, request, view, obj):
"""
視圖繼承GenericAPIView,并在其中使用get_object時獲取對象時,觸發單獨對象權限驗證
Return `True` if permission is granted, `False` otherwise.
:param request:
:param view:
:param obj:
:return: True有權限;False無權限
"""
if request.user == "管理員":
return True
class TestView(APIView):
# 認證的動作是由request.user觸發
authentication_classes = [TestAuthentication, ]
# 權限
# 循環執行所有的權限
permission_classes = [TestPermission, ]
def get(self, request, *args, **kwargs):
# self.dispatch
print(request.user)
print(request.auth)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
e. 全局使用
上述操作中均是對單獨視圖進行特殊配置,如果想要對全局進行配置,則需要再配置文件中寫入即可。
settings.py
REST_FRAMEWORK = {
'UNAUTHENTICATED_USER': None,
'UNAUTHENTICATED_TOKEN': None,
"DEFAULT_AUTHENTICATION_CLASSES": [
"web.utils.TestAuthentication",
],
"DEFAULT_PERMISSION_CLASSES": [
"web.utils.TestPermission",
],
}
settings.py
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view()),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
class TestView(APIView):
def get(self, request, *args, **kwargs):
# self.dispatch
print(request.user)
print(request.auth)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
3. 用戶訪問次數/頻率限制
a、基于用戶IP限制訪問頻率
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view()),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import time
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework.throttling import BaseThrottle
from rest_framework.settings import api_settings
# 保存訪問記錄
RECORD = {
'用戶IP': [12312139, 12312135, 12312133, ]
}
class TestThrottle(BaseThrottle):
ctime = time.time
def get_ident(self, request):
"""
根據用戶IP和代理IP,當做請求者的唯一IP
Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR
if present and number of proxies is > 0. If not use all of
HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR.
"""
xff = request.META.get('HTTP_X_FORWARDED_FOR')
remote_addr = request.META.get('REMOTE_ADDR')
num_proxies = api_settings.NUM_PROXIES
if num_proxies is not None:
if num_proxies == 0 or xff is None:
return remote_addr
addrs = xff.split(',')
client_addr = addrs[-min(num_proxies, len(addrs))]
return client_addr.strip()
return ''.join(xff.split()) if xff else remote_addr
def allow_request(self, request, view):
"""
是否仍然在允許范圍內
Return `True` if the request should be allowed, `False` otherwise.
:param request:
:param view:
:return: True,表示可以通過;False表示已超過限制,不允許訪問
"""
# 獲取用戶唯一標識(如:IP)
# 允許一分鐘訪問10次
num_request = 10
time_request = 60
now = self.ctime()
ident = self.get_ident(request)
self.ident = ident
if ident not in RECORD:
RECORD[ident] = [now, ]
return True
history = RECORD[ident]
while history and history[-1] <= now - time_request:
history.pop()
if len(history) < num_request:
history.insert(0, now)
return True
def wait(self):
"""
多少秒后可以允許繼續訪問
Optionally, return a recommended number of seconds to wait before
the next request.
"""
last_time = RECORD[self.ident][0]
now = self.ctime()
return int(60 + last_time - now)
class TestView(APIView):
throttle_classes = [TestThrottle, ]
def get(self, request, *args, **kwargs):
# self.dispatch
print(request.user)
print(request.auth)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
def throttled(self, request, wait):
"""
訪問次數被限制時,定制錯誤信息
"""
class Throttled(exceptions.Throttled):
default_detail = '請求被限制.'
extra_detail_singular = '請 {wait} 秒之后再重試.'
extra_detail_plural = '請 {wait} 秒之后再重試.'
raise Throttled(wait)
views.py
b、基于用戶IP顯示訪問頻率(利用Django緩存)
settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'test_scope': '10/m',
},
}
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view()),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework.throttling import SimpleRateThrottle
class TestThrottle(SimpleRateThrottle):
# 配置文件定義的顯示頻率的Key
scope = "test_scope"
def get_cache_key(self, request, view):
"""
Should return a unique cache-key which can be used for throttling.
Must be overridden.
May return `None` if the request should not be throttled.
"""
if not request.user:
ident = self.get_ident(request)
else:
ident = request.user
return self.cache_format % {
'scope': self.scope,
'ident': ident
}
class TestView(APIView):
throttle_classes = [TestThrottle, ]
def get(self, request, *args, **kwargs):
# self.dispatch
print(request.user)
print(request.auth)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
def throttled(self, request, wait):
"""
訪問次數被限制時,定制錯誤信息
"""
class Throttled(exceptions.Throttled):
default_detail = '請求被限制.'
extra_detail_singular = '請 {wait} 秒之后再重試.'
extra_detail_plural = '請 {wait} 秒之后再重試.'
raise Throttled(wait)
views.py
c、view中限制請求頻率
settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'xxxxxx': '10/m',
},
}
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view()),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework.throttling import ScopedRateThrottle
# 繼承 ScopedRateThrottle
class TestThrottle(ScopedRateThrottle):
def get_cache_key(self, request, view):
"""
Should return a unique cache-key which can be used for throttling.
Must be overridden.
May return `None` if the request should not be throttled.
"""
if not request.user:
ident = self.get_ident(request)
else:
ident = request.user
return self.cache_format % {
'scope': self.scope,
'ident': ident
}
class TestView(APIView):
throttle_classes = [TestThrottle, ]
# 在settings中獲取 xxxxxx 對應的頻率限制值
throttle_scope = "xxxxxx"
def get(self, request, *args, **kwargs):
# self.dispatch
print(request.user)
print(request.auth)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
def throttled(self, request, wait):
"""
訪問次數被限制時,定制錯誤信息
"""
class Throttled(exceptions.Throttled):
default_detail = '請求被限制.'
extra_detail_singular = '請 {wait} 秒之后再重試.'
extra_detail_plural = '請 {wait} 秒之后再重試.'
raise Throttled(wait)
views.py
d. 匿名時用IP限制+登錄時用Token限制
settings.py
REST_FRAMEWORK = {
'UNAUTHENTICATED_USER': None,
'UNAUTHENTICATED_TOKEN': None,
'DEFAULT_THROTTLE_RATES': {
'luffy_anon': '10/m',
'luffy_user': '20/m',
},
}
settings.py
urls.py
from django.conf.urls import url, include
from web.views.s3_throttling import TestView
urlpatterns = [
url(r'^test/', TestView.as_view()),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.throttling import SimpleRateThrottle
class LuffyAnonRateThrottle(SimpleRateThrottle):
"""
匿名用戶,根據IP進行限制
"""
scope = "luffy_anon"
def get_cache_key(self, request, view):
# 用戶已登錄,則跳過 匿名頻率限制
if request.user:
return None
return self.cache_format % {
'scope': self.scope,
'ident': self.get_ident(request)
}
class LuffyUserRateThrottle(SimpleRateThrottle):
"""
登錄用戶,根據用戶token限制
"""
scope = "luffy_user"
def get_ident(self, request):
"""
認證成功時:request.user是用戶對象;request.auth是token對象
:param request:
:return:
"""
# return request.auth.token
return "user_token"
def get_cache_key(self, request, view):
"""
獲取緩存key
:param request:
:param view:
:return:
"""
# 未登錄用戶,則跳過 Token限制
if not request.user:
return None
return self.cache_format % {
'scope': self.scope,
'ident': self.get_ident(request)
}
class TestView(APIView):
throttle_classes = [LuffyUserRateThrottle, LuffyAnonRateThrottle, ]
def get(self, request, *args, **kwargs):
# self.dispatch
print(request.user)
print(request.auth)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
e. 全局使用
settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'api.utils.throttles.throttles.LuffyAnonRateThrottle',
'api.utils.throttles.throttles.LuffyUserRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'anon': '10/day',
'user': '10/day',
'luffy_anon': '10/m',
'luffy_user': '20/m',
},
}
settings
4、版本
a. 基于url的get傳參方式
如:/users?version=v1
REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默認版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允許的版本
'VERSION_PARAM': 'version' # URL中獲取值的key
}
settings.py
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view(),name='test'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import QueryParameterVersioning
class TestView(APIView):
versioning_class = QueryParameterVersioning
def get(self, request, *args, **kwargs):
# 獲取版本
print(request.version)
# 獲取版本管理的類
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request)
print(reverse_url)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
b. 基于url的正則方式
如:/v1/users/
settings.py
REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默認版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允許的版本
'VERSION_PARAM': 'version' # URL中獲取值的key
}
settings.py
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import URLPathVersioning
class TestView(APIView):
versioning_class = URLPathVersioning
def get(self, request, *args, **kwargs):
# 獲取版本
print(request.version)
# 獲取版本管理的類
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request)
print(reverse_url)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
c. 基于 accept 請求頭方式
如:Accept: application/json; version=1.0
settings.py
REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默認版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允許的版本
'VERSION_PARAM': 'version' # URL中獲取值的key
}
settings.py
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view(), name='test'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import AcceptHeaderVersioning
class TestView(APIView):
versioning_class = AcceptHeaderVersioning
def get(self, request, *args, **kwargs):
# 獲取版本 HTTP_ACCEPT頭
print(request.version)
# 獲取版本管理的類
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request)
print(reverse_url)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
d. 基于主機名方法
如:v1.example.com
settings.py
ALLOWED_HOSTS = ['*']
REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默認版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允許的版本
'VERSION_PARAM': 'version' # URL中獲取值的key
}
settings.py
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^test/', TestView.as_view(), name='test'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import HostNameVersioning
class TestView(APIView):
versioning_class = HostNameVersioning
def get(self, request, *args, **kwargs):
# 獲取版本
print(request.version)
# 獲取版本管理的類
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request)
print(reverse_url)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
e. 基于django路由系統的namespace
如:example.com/v1/users/
settings.py
REST_FRAMEWORK = {
'DEFAULT_VERSION': 'v1', # 默認版本
'ALLOWED_VERSIONS': ['v1', 'v2'], # 允許的版本
'VERSION_PARAM': 'version' # URL中獲取值的key
}
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'^v1/', ([
url(r'test/', TestView.as_view(), name='test'),
], None, 'v1')),
url(r'^v2/', ([
url(r'test/', TestView.as_view(), name='test'),
], None, 'v2')),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.versioning import NamespaceVersioning
class TestView(APIView):
versioning_class = NamespaceVersioning
def get(self, request, *args, **kwargs):
# 獲取版本
print(request.version)
# 獲取版本管理的類
print(request.versioning_scheme)
# 反向生成URL
reverse_url = request.versioning_scheme.reverse('test', request=request)
print(reverse_url)
return Response('GET請求,響應內容')
def post(self, request, *args, **kwargs):
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
f. 全局使用
settings.py
REST_FRAMEWORK = {
'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
'DEFAULT_VERSION': 'v1',
'ALLOWED_VERSIONS': ['v1', 'v2'],
'VERSION_PARAM': 'version'
}
settings.py
5. 解析器
根據請求頭 content-type 選擇對應的解析器就請求體內容進行處理。
a. 僅處理請求頭content-type為application/json的請求體
urls.py
from django.conf.urls import url, include
from web.views.s5_parser import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
urls.py
views.py
from django.conf.urls import url, include
from web.views.s5_parser import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
urls.py
b. 僅處理請求頭content-type為application/x-www-form-urlencoded 的請求體
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import FormParser
class TestView(APIView):
parser_classes = [FormParser, ]
def post(self, request, *args, **kwargs):
print(request.content_type)
# 獲取請求的值,并使用對應的JSONParser進行處理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
c. 僅處理請求頭content-type為multipart/form-data的請求體
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import MultiPartParser
class TestView(APIView):
parser_classes = [MultiPartParser, ]
def post(self, request, *args, **kwargs):
print(request.content_type)
# 獲取請求的值,并使用對應的JSONParser進行處理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data">
<input type="text" name="user" />
<input type="file" name="img">
<input type="submit" value="提交">
</form>
</body>
</html>
upload.html
d. 僅上傳文件
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import FileUploadParser
class TestView(APIView):
parser_classes = [FileUploadParser, ]
def post(self, request, filename, *args, **kwargs):
print(filename)
print(request.content_type)
# 獲取請求的值,并使用對應的JSONParser進行處理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data">
<input type="text" name="user" />
<input type="file" name="img">
<input type="submit" value="提交">
</form>
</body>
</html>
upload.html
e. 同時多個Parser
當同時使用多個parser時,rest framework會根據請求頭content-type自動進行比對,并使用對應parser
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
class TestView(APIView):
parser_classes = [JSONParser, FormParser, MultiPartParser, ]
def post(self, request, *args, **kwargs):
print(request.content_type)
# 獲取請求的值,并使用對應的JSONParser進行處理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
f. 全局使用
settings.py
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES':[
'rest_framework.parsers.JSONParser'
'rest_framework.parsers.FormParser'
'rest_framework.parsers.MultiPartParser'
]
}
settings.py
urls.py
from django.conf.urls import url, include
from web.views import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
class TestView(APIView):
def post(self, request, *args, **kwargs):
print(request.content_type)
# 獲取請求的值,并使用對應的JSONParser進行處理
print(request.data)
# application/x-www-form-urlencoded 或 multipart/form-data時,request.POST中才有值
print(request.POST)
print(request.FILES)
return Response('POST請求,響應內容')
def put(self, request, *args, **kwargs):
return Response('PUT請求,響應內容')
views.py
注意:個別特殊的值可以通過Django的request對象 request._request 來進行獲取
6、序列化
official link:http://www.django-rest-framework.org/api-guide/serializers/
Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can ten be easily rendered into Json,XML or other content types. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.
Attention:
The serializers in REST framework work very simliarly to Django's Form and ModelForm classes.
序列化用于對用戶請求數據進行驗證和數據進行序列化
a、自定義字段
urls.py
from django.conf.urls import url, include
from web.views.s6_serializers import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from .. import models
class PasswordValidator(object):
def __init__(self, base):
self.base = base
def __call__(self, value):
if value != self.base:
message = 'This field must be %s.' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
"""
This hook is called by the serializer instance,
prior to the validation call being made.
"""
# 執行驗證之前調用,serializer_fields是當前字段對象
pass
class UserSerializer(serializers.Serializer):
ut_title = serializers.CharField(source='ut.title')
user = serializers.CharField(min_length=6)
pwd = serializers.CharField(error_messages={'required': '密碼不能為空'}, validators=[PasswordValidator('666')])
class TestView(APIView):
def get(self, request, *args, **kwargs):
# 序列化,將數據庫查詢字段序列化為字典
data_list = models.UserInfo.objects.all()
ser = UserSerializer(instance=data_list, many=True)
# 或
# obj = models.UserInfo.objects.all().first()
# ser = UserSerializer(instance=obj, many=False)
return Response(ser.data)
def post(self, request, *args, **kwargs):
# 驗證,對請求發來的數據進行驗證
ser = UserSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
else:
print(ser.errors)
return Response('POST請求,響應內容')
views.py
b. 基于Model自動生成字段
from django.conf.urls import url, include
from web.views.s6_serializers import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from .. import models
class PasswordValidator(object):
def __init__(self, base):
self.base = str(base)
def __call__(self, value):
if value != self.base:
message = 'This field must be %s.' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
"""
This hook is called by the serializer instance,
prior to the validation call being made.
"""
# 執行驗證之前調用,serializer_fields是當前字段對象
pass
class ModelUserSerializer(serializers.ModelSerializer):
user = serializers.CharField(max_length=32)
class Meta:
model = models.UserInfo
fields = "__all__"
# fields = ['user', 'pwd', 'ut']
depth = 2
extra_kwargs = {'user': {'min_length': 6}, 'pwd': {'validators': [PasswordValidator(666), ]}}
# read_only_fields = ['user']
class TestView(APIView):
def get(self, request, *args, **kwargs):
# 序列化,將數據庫查詢字段序列化為字典
data_list = models.UserInfo.objects.all()
ser = ModelUserSerializer(instance=data_list, many=True)
# 或
# obj = models.UserInfo.objects.all().first()
# ser = UserSerializer(instance=obj, many=False)
return Response(ser.data)
def post(self, request, *args, **kwargs):
# 驗證,對請求發來的數據進行驗證
print(request.data)
ser = ModelUserSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
else:
print(ser.errors)
return Response('POST請求,響應內容')
views.py
c. 生成URL
urls.py
from django.conf.urls import url, include
from web.views.s6_serializers import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='detail'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from .. import models
class PasswordValidator(object):
def __init__(self, base):
self.base = str(base)
def __call__(self, value):
if value != self.base:
message = 'This field must be %s.' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
"""
This hook is called by the serializer instance,
prior to the validation call being made.
"""
# 執行驗證之前調用,serializer_fields是當前字段對象
pass
class ModelUserSerializer(serializers.ModelSerializer):
ut = serializers.HyperlinkedIdentityField(view_name='detail')
class Meta:
model = models.UserInfo
fields = "__all__"
extra_kwargs = {
'user': {'min_length': 6},
'pwd': {'validators': [PasswordValidator(666),]},
}
class TestView(APIView):
def get(self, request, *args, **kwargs):
# 序列化,將數據庫查詢字段序列化為字典
data_list = models.UserInfo.objects.all()
ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request})
# 或
# obj = models.UserInfo.objects.all().first()
# ser = UserSerializer(instance=obj, many=False)
return Response(ser.data)
def post(self, request, *args, **kwargs):
# 驗證,對請求發來的數據進行驗證
print(request.data)
ser = ModelUserSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
else:
print(ser.errors)
return Response('POST請求,響應內容')
views.py
d. 自動生成URL
urls.py
from django.conf.urls import url, include
from web.views.s6_serializers import TestView
urlpatterns = [
url(r'test/', TestView.as_view(), name='test'),
url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='xxxx'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from .. import models
class PasswordValidator(object):
def __init__(self, base):
self.base = str(base)
def __call__(self, value):
if value != self.base:
message = 'This field must be %s.' % self.base
raise serializers.ValidationError(message)
def set_context(self, serializer_field):
"""
This hook is called by the serializer instance,
prior to the validation call being made.
"""
# 執行驗證之前調用,serializer_fields是當前字段對象
pass
class ModelUserSerializer(serializers.HyperlinkedModelSerializer):
ll = serializers.HyperlinkedIdentityField(view_name='xxxx')
tt = serializers.CharField(required=False)
class Meta:
model = models.UserInfo
fields = "__all__"
list_serializer_class = serializers.ListSerializer
extra_kwargs = {
'user': {'min_length': 6},
'pwd': {'validators': [PasswordValidator(666), ]},
'url': {'view_name': 'xxxx'},
'ut': {'view_name': 'xxxx'},
}
class TestView(APIView):
def get(self, request, *args, **kwargs):
# # 序列化,將數據庫查詢字段序列化為字典
data_list = models.UserInfo.objects.all()
ser = ModelUserSerializer(instance=data_list, many=True, context={'request': request})
# # 如果Many=True
# # 或
# # obj = models.UserInfo.objects.all().first()
# # ser = UserSerializer(instance=obj, many=False)
return Response(ser.data)
def post(self, request, *args, **kwargs):
# 驗證,對請求發來的數據進行驗證
print(request.data)
ser = ModelUserSerializer(data=request.data)
if ser.is_valid():
print(ser.validated_data)
else:
print(ser.errors)
return Response('POST請求,響應內容')
views.py
7、分頁
a. 根據頁碼進行分頁
urls.py
from django.conf.urls import url, include
from rest_framework import routers
from web.views import s9_pagination
urlpatterns = [
url(r'^test/', s9_pagination.UserViewSet.as_view()),
]
urs.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework import serializers
from .. import models
from rest_framework.pagination import PageNumberPagination
class StandardResultsSetPagination(PageNumberPagination):
# 默認每頁顯示的數據條數
page_size = 1
# 獲取URL參數中設置的每頁顯示數據條數
page_size_query_param = 'page_size'
# 獲取URL參數中傳入的頁碼key
page_query_param = 'page'
# 最大支持的每頁顯示的數據條數
max_page_size = 1
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserViewSet(APIView):
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().order_by('-id')
# 實例化分頁對象,獲取數據庫中的分頁數據
paginator = StandardResultsSetPagination()
page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)
# 序列化對象
serializer = UserSerializer(page_user_list, many=True)
# 生成分頁和數據
response = paginator.get_paginated_response(serializer.data)
return response
views.py
b. 位置和個數進行分頁
url.py
from django.conf.urls import url, include
from web.views import s9_pagination
urlpatterns = [
url(r'^test/', s9_pagination.UserViewSet.as_view()),
]
urls.py
view.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework import serializers
from .. import models
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
class StandardResultsSetPagination(LimitOffsetPagination):
# 默認每頁顯示的數據條數
default_limit = 10
# URL中傳入的顯示數據條數的參數
limit_query_param = 'limit'
# URL中傳入的數據位置的參數
offset_query_param = 'offset'
# 最大每頁顯得條數
max_limit = None
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserViewSet(APIView):
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().order_by('-id')
# 實例化分頁對象,獲取數據庫中的分頁數據
paginator = StandardResultsSetPagination()
page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)
# 序列化對象
serializer = UserSerializer(page_user_list, many=True)
# 生成分頁和數據
response = paginator.get_paginated_response(serializer.data)
return response
views.py
c. 游標分頁
from django.conf.urls import url, include
from web.views import s9_pagination
urlpatterns = [
url(r'^test/', s9_pagination.UserViewSet.as_view()),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework import serializers
from .. import models
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
class StandardResultsSetPagination(CursorPagination):
# URL傳入的游標參數
cursor_query_param = 'cursor'
# 默認每頁顯示的數據條數
page_size = 2
# URL傳入的每頁顯示條數的參數
page_size_query_param = 'page_size'
# 每頁顯示數據最大條數
max_page_size = 1000
# 根據ID從大到小排列
ordering = "id"
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserViewSet(APIView):
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().order_by('-id')
# 實例化分頁對象,獲取數據庫中的分頁數據
paginator = StandardResultsSetPagination()
page_user_list = paginator.paginate_queryset(user_list, self.request, view=self)
# 序列化對象
serializer = UserSerializer(page_user_list, many=True)
# 生成分頁和數據
response = paginator.get_paginated_response(serializer.data)
return response
views.py
8、路由系統
a.自定義路由
urls.py
from django.conf.urls import url, include
from web.views import s11_render
urlpatterns = [
url(r'^test/$', s11_render.TestView.as_view()),
url(r'^test\.(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view()),
url(r'^test/(?P<pk>[^/.]+)/$', s11_render.TestView.as_view()),
url(r'^test/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view())
]
urls.py
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from .. import models
class TestView(APIView):
def get(self, request, *args, **kwargs):
print(kwargs)
print(self.renderer_classes)
return Response('...')
views.py
b. 半自動路由
urls.py
from django.conf.urls import url, include
from web.views import s10_generic
urlpatterns = [
url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view(
{'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers
from .. import models
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserViewSet(ModelViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserSerializer
views.py
c. 全自動路由
urls.py
from django.conf.urls import url, include
from rest_framework import routers
from web.views import s10_generic
router = routers.DefaultRouter()
router.register(r'users', s10_generic.UserViewSet)
urlpatterns = [
url(r'^', include(router.urls)),
]
urls.py
views.py
from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers
from .. import models
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserViewSet(ModelViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserSerializer
views.py
9. 視圖
a. GenericViewSet
urls.py
from django.conf.urls import url, include
from web.views.s7_viewset import TestView
urlpatterns = [
url(r'test/', TestView.as_view({'get':'list'}), name='test'),
url(r'detail/(?P<pk>\d+)/', TestView.as_view({'get':'list'}), name='xxxx'),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework import viewsets
from rest_framework.response import Response
class TestView(viewsets.GenericViewSet):
def list(self, request, *args, **kwargs):
return Response('...')
def add(self, request, *args, **kwargs):
pass
def delete(self, request, *args, **kwargs):
pass
def edit(self, request, *args, **kwargs):
pass
views.py
b. ModelViewSet(自定義URL)
from django.conf.urls import url, include
from web.views import s10_generic
urlpatterns = [
url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
url(r'^test/(?P<pk>\d+)/$', s10_generic.UserViewSet.as_view(
{'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.viewsets import ModelViewSet
from rest_framework import serializers
from .. import models
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class UserViewSet(ModelViewSet):
queryset = models.UserInfo.objects.all()
serializer_class = UserSerializer
views.py
c. ModelViewSet(rest framework路由)
urls.py
from django.conf.urls import url, include
from rest_framework import routers
from app01 import views
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'groups', views.GroupViewSet)
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
url(r'^', include(router.urls)),
]
urls.py
views.py
from rest_framework import viewsets
from rest_framework import serializers
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.User
fields = ('url', 'username', 'email', 'groups')
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = models.Group
fields = ('url', 'name')
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 groups to be viewed or edited.
"""
queryset = Group.objects.all()
serializer_class = GroupSerializer
views.py
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
a. 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/
urls.py
from django.conf.urls import url, include
from web.views import s11_render
urlpatterns = [
url(r'^test/$', s11_render.TestView.as_view()),
url(r'^test\.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.renderers import JSONRenderer
from .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class TestView(APIView):
renderer_classes = [JSONRenderer, ]
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all()
ser = TestSerializer(instance=user_list, many=True)
return Response(ser.data)
views.py
b. 表格
訪問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/
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.renderers import AdminRenderer
from .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class TestView(APIView):
renderer_classes = [AdminRenderer, ]
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all()
ser = TestSerializer(instance=user_list, many=True)
return Response(ser.data)
views.py
c. 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/
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.renderers import JSONRenderer
from rest_framework.renderers import AdminRenderer
from rest_framework.renderers import HTMLFormRenderer
from .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class TestView(APIView):
renderer_classes = [HTMLFormRenderer, ]
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().first()
ser = TestSerializer(instance=user_list, many=False)
return Response(ser.data)
views.py
d. 自定義顯示模板
訪問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/
urls.py
from django.conf.urls import url, include
from web.views import s11_render
urlpatterns = [
url(r'^test/$', s11_render.TestView.as_view()),
url(r'^test\.(?P<format>[a-z0-9]+)', s11_render.TestView.as_view()),
]
urls.py
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.renderers import TemplateHTMLRenderer
from .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class TestView(APIView):
renderer_classes = [TemplateHTMLRenderer, ]
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().first()
ser = TestSerializer(instance=user_list, many=False)
return Response(ser.data, template_name='user_detail.html')
views.py
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ user }}
{{ pwd }}
{{ ut }}
</body>
</html>
userdetail.html
e. 瀏覽器格式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/
views.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import serializers
from rest_framework.renderers import JSONRenderer
from rest_framework.renderers import BrowsableAPIRenderer
from .. import models
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = models.UserInfo
fields = "__all__"
class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):
def get_default_renderer(self, view):
return JSONRenderer()
class TestView(APIView):
renderer_classes = [CustomBrowsableAPIRenderer, ]
def get(self, request, *args, **kwargs):
user_list = models.UserInfo.objects.all().first()
ser = TestSerializer(instance=user_list, many=False)
return Response(ser.data, template_name='user_detail.html')
views.py