Django Rest Framework(一)
一、什么是RESTful
REST與技術無關,代表一種軟件架構風格,REST是Representational State Transfer的簡稱,中文翻譯為“表征狀態轉移”。
REST從資源的角度審視整個網絡,它將分布在網絡中某個節點的資源通過URL進行標識,客戶端應用通過URL來獲取資源的表征,獲取這些表征致使這些應用轉變狀態。
所有的數據,不管是通過網絡獲取的還是操作(增刪改查)的數據都是資源,將一切數據視為資源是REST區別于其他架構風格的最本質屬性。
對于REST這種面向資源的架構風格,有人提出一種全新的結構理念,即面向資源架構(ROA:Resource Oriented Architecture)。
?
二、RESTful API設計
1.API與用戶的通信協議,總是使用HTTPS協議。
2.域名
- https://api.example.com ?盡量將API部署在專用域名(會存在跨域問題)
- https://example.org ?API很簡單
3.路徑,視網絡上任何東西都是資源,均使用名詞表示(可復數)
- https://api.example.com/v1/zoos
- https://api.example.com/v1/animals
4.method
- GET ?從服務器取資源(一項或多項)
- POST ?在服務器新建一個資源
- PUT ?在服務器更新資源(客戶端提供改變后的完整資源)
- PATCH ?在服務器更新資源(客戶端提供改變的屬性)
- DELETE ?從服務器刪除資源
5.過濾,通過在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:指定篩選條件
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 常用狀態碼列表7.錯誤處理,狀態碼是4XX時,應返回錯誤信息,error當作key
{error: "Invalid API key" } View Code8.返回結果,針對不同操作,服務器向用戶返回的結果應該符合以下規范。
GET /collection:返回資源對象的列表(數組) GET /collection/resource:返回單個資源對象 POST /collection:返回新生成的資源對象 PUT /collection/resource:返回完整的資源對象 PATCH /collection/resource:返回完整的資源對象 DELETE /collection/resource:返回一個空文檔 View Code9.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" }} View Code摘自:http://www.ruanyifeng.com/blog/2014/05/restful_api.html?
?
三、基于Django實現
路由系統:
urlpatterns = [url(r'^users', Users.as_view()), ] View CodeCBV視圖:
from django.views import View from django.http import JsonResponseclass 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) View Code?
四、基于Django Rest framework框架實現
1.基本流程
from django.conf.urls import url, include from web.views.s1_api import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ] url.py from rest_framework.views import APIView from rest_framework.response import Responseclass 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請求,響應內容') views.py上述是rest framework框架基本流程,重要的功能是在APIview的dispatch中觸發。
?
2.認證和授權
(1)用戶url傳入的token認證
from django.conf.urls import url, include from web.viewsimport TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ] urls.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 exceptionstoken_list = ['sfsfss123kuf3j123','asijnfowerkkf9812', ]class TestAuthentication(BaseAuthentication):def authenticate(self, request):"""用戶認證,如果驗證成功后返回元組: (用戶,用戶Token):param request: :return: None,表示跳過該驗證;如果跳過了所有認證,默認用戶和Token和使用配置文件進行設置self._authenticator = Noneif api_settings.UNAUTHENTICATED_USER:self.user = api_settings.UNAUTHENTICATED_USER()else:self.user = Noneif 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 theauthentication scheme should return `403 Permission Denied` responses."""# 驗證失敗時,返回的響應頭WWW-Authenticate對應的值passclass 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(2)請求頭認證
from django.conf.urls import url, include from web.viewsimport TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ] urls.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 exceptionstoken_list = ['sfsfss123kuf3j123','asijnfowerkkf9812', ]class TestAuthentication(BaseAuthentication):def authenticate(self, request):"""用戶認證,如果驗證成功后返回元組: (用戶,用戶Token):param request: :return: None,表示跳過該驗證;如果跳過了所有認證,默認用戶和Token和使用配置文件進行設置self._authenticator = Noneif api_settings.UNAUTHENTICATED_USER:self.user = api_settings.UNAUTHENTICATED_USER()else:self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN:self.auth = api_settings.UNAUTHENTICATED_TOKEN()else:self.auth = None(user,token)表示驗證通過并設置用戶名和Token;AuthenticationFailed異常"""import base64auth = 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 theauthentication 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(3)多個認證規則
from django.conf.urls import url, include from web.views.s2_auth import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ] urls.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 exceptionstoken_list = ['sfsfss123kuf3j123','asijnfowerkkf9812', ]class Test1Authentication(BaseAuthentication):def authenticate(self, request):"""用戶認證,如果驗證成功后返回元組: (用戶,用戶Token):param request: :return: None,表示跳過該驗證;如果跳過了所有認證,默認用戶和Token和使用配置文件進行設置self._authenticator = Noneif api_settings.UNAUTHENTICATED_USER:self.user = api_settings.UNAUTHENTICATED_USER() # 默認值為:匿名用戶else:self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN:self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默認值為:Noneelse:self.auth = None(user,token)表示驗證通過并設置用戶名和Token;AuthenticationFailed異常"""import base64auth = request.META.get('HTTP_AUTHORIZATION', b'')if auth:auth = auth.encode('utf-8')else:return Noneprint(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 theauthentication scheme should return `403 Permission Denied` responses."""# return 'Basic realm=api'passclass Test2Authentication(BaseAuthentication):def authenticate(self, request):"""用戶認證,如果驗證成功后返回元組: (用戶,用戶Token):param request: :return: None,表示跳過該驗證;如果跳過了所有認證,默認用戶和Token和使用配置文件進行設置self._authenticator = Noneif api_settings.UNAUTHENTICATED_USER:self.user = api_settings.UNAUTHENTICATED_USER() # 默認值為:匿名用戶else:self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN:self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默認值為:Noneelse: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 theauthentication scheme should return `403 Permission Denied` responses."""passclass 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(4)認證和權限
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ] urls.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 BasePermissionfrom rest_framework.request import Request from rest_framework import exceptionstoken_list = ['sfsfss123kuf3j123','asijnfowerkkf9812', ]class TestAuthentication(BaseAuthentication):def authenticate(self, request):"""用戶認證,如果驗證成功后返回元組: (用戶,用戶Token):param request: :return: None,表示跳過該驗證;如果跳過了所有認證,默認用戶和Token和使用配置文件進行設置self._authenticator = Noneif api_settings.UNAUTHENTICATED_USER:self.user = api_settings.UNAUTHENTICATED_USER() # 默認值為:匿名用戶else:self.user = Noneif api_settings.UNAUTHENTICATED_TOKEN:self.auth = api_settings.UNAUTHENTICATED_TOKEN()# 默認值為:Noneelse: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 theauthentication scheme should return `403 Permission Denied` responses."""passclass 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 Trueclass TestView(APIView):# 認證的動作是由request.user觸發authentication_classes = [TestAuthentication, ]# 權限# 循環執行所有的權限permission_classes = [TestPermission, ]def get(self, request, *args, **kwargs):# self.dispatchprint(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(5)全局使用
上述操作中均是對單獨試圖進行特殊操作配置,如果要對全局進行配置,則需要在配置文件中寫入即可。
REST_FRAMEWORK = {'UNAUTHENTICATED_USER': None,'UNAUTHENTICATED_TOKEN': None,"DEFAULT_AUTHENTICATION_CLASSES": ["web.utils.TestAuthentication",],"DEFAULT_PERMISSION_CLASSES": ["web.utils.TestPermission",], } settings.py from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ] urls.py #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Responseclass TestView(APIView):def get(self, request, *args, **kwargs):# self.dispatchprint(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.用戶訪問次數/頻率限制
(1)基于用戶IP限制訪問頻率
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ] urls.py #!/usr/bin/env python # -*- coding:utf-8 -*- import time from rest_framework.views import APIView from rest_framework.response import Responsefrom 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.timedef get_ident(self, request):"""根據用戶IP和代理IP,當做請求者的唯一IPIdentify the machine making the request by parsing HTTP_X_FORWARDED_FORif present and number of proxies is > 0. If not use all ofHTTP_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_PROXIESif num_proxies is not None:if num_proxies == 0 or xff is None:return remote_addraddrs = xff.split(',')client_addr = addrs[-min(num_proxies, len(addrs))]return client_addr.strip()return ''.join(xff.split()) if xff else remote_addrdef 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 = 10time_request = 60now = self.ctime()ident = self.get_ident(request)self.ident = identif ident not in RECORD:RECORD[ident] = [now, ]return Truehistory = RECORD[ident]while history and history[-1] <= now - time_request:history.pop()if len(history) < num_request:history.insert(0, now)return Truedef wait(self):"""多少秒后可以允許繼續訪問Optionally, return a recommended number of seconds to wait beforethe 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.dispatchprint(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(2)基于用戶IP顯示訪問頻率(利用Django緩存)
REST_FRAMEWORK = {'DEFAULT_THROTTLE_RATES': {'test_scope': '10/m',}, } settings.py from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ] urls.py #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Responsefrom rest_framework import exceptions from rest_framework.throttling import SimpleRateThrottleclass TestThrottle(SimpleRateThrottle):# 配置文件定義的顯示頻率的Keyscope = "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.userreturn self.cache_format % {'scope': self.scope,'ident': ident}class TestView(APIView):throttle_classes = [TestThrottle, ]def get(self, request, *args, **kwargs):# self.dispatchprint(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(3)view中限制請求頻率
REST_FRAMEWORK = {'DEFAULT_THROTTLE_RATES': {'xxxxxx': '10/m',}, } settings.py from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ] urls.py #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Responsefrom 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.userreturn 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.dispatchprint(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(4)匿名時用IP限制+登錄時用Token限制
REST_FRAMEWORK = {'UNAUTHENTICATED_USER': None,'UNAUTHENTICATED_TOKEN': None,'DEFAULT_THROTTLE_RATES': {'luffy_anon': '10/m','luffy_user': '20/m',}, } settings.py from django.conf.urls import url, include from web.views.s3_throttling import TestViewurlpatterns = [url(r'^test/', TestView.as_view()), ] urls.py #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Responsefrom rest_framework.throttling import SimpleRateThrottleclass LuffyAnonRateThrottle(SimpleRateThrottle):"""匿名用戶,根據IP進行限制"""scope = "luffy_anon"def get_cache_key(self, request, view):# 用戶已登錄,則跳過 匿名頻率限制if request.user:return Nonereturn 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.tokenreturn "user_token"def get_cache_key(self, request, view):"""獲取緩存key:param request: :param view: :return: """# 未登錄用戶,則跳過 Token限制if not request.user:return Nonereturn 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.dispatchprint(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(5)全局使用
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.版本
(1)基于url的get傳參方式
如:/users?version=v1
REST_FRAMEWORK = {'DEFAULT_VERSION': 'v1', # 默認版本'ALLOWED_VERSIONS': ['v1', 'v2'], # 允許的版本'VERSION_PARAM': 'version' # URL中獲取值的key } settings.py from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view(),name='test'), ] urls.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 QueryParameterVersioningclass TestView(APIView):versioning_class = QueryParameterVersioningdef get(self, request, *args, **kwargs):# 獲取版本print(request.version)# 獲取版本管理的類print(request.versioning_scheme)# 反向生成URLreverse_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(2)基于url的正則方式
如:/v1/users/
REST_FRAMEWORK = {'DEFAULT_VERSION': 'v1', # 默認版本'ALLOWED_VERSIONS': ['v1', 'v2'], # 允許的版本'VERSION_PARAM': 'version' # URL中獲取值的key } settings.py from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'), ] urls.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 URLPathVersioningclass TestView(APIView):versioning_class = URLPathVersioningdef get(self, request, *args, **kwargs):# 獲取版本print(request.version)# 獲取版本管理的類print(request.versioning_scheme)# 反向生成URLreverse_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(3)基于accept請求方式
如:Accept: application/json; version=1.0
REST_FRAMEWORK = {'DEFAULT_VERSION': 'v1', # 默認版本'ALLOWED_VERSIONS': ['v1', 'v2'], # 允許的版本'VERSION_PARAM': 'version' # URL中獲取值的key } settings.py from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view(), name='test'), ] urls.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 AcceptHeaderVersioningclass TestView(APIView):versioning_class = AcceptHeaderVersioningdef get(self, request, *args, **kwargs):# 獲取版本 HTTP_ACCEPT頭print(request.version)# 獲取版本管理的類print(request.versioning_scheme)# 反向生成URLreverse_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(4)基于主機名方法
如:v1.example.com
ALLOWED_HOSTS = ['*'] REST_FRAMEWORK = {'DEFAULT_VERSION': 'v1', # 默認版本'ALLOWED_VERSIONS': ['v1', 'v2'], # 允許的版本'VERSION_PARAM': 'version' # URL中獲取值的key } settings.py from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'^test/', TestView.as_view(), name='test'), ] urls.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 HostNameVersioningclass TestView(APIView):versioning_class = HostNameVersioningdef get(self, request, *args, **kwargs):# 獲取版本print(request.version)# 獲取版本管理的類print(request.versioning_scheme)# 反向生成URLreverse_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(5)基于Django路由系統的namespace
如:example.com/v1/users/
REST_FRAMEWORK = {'DEFAULT_VERSION': 'v1', # 默認版本'ALLOWED_VERSIONS': ['v1', 'v2'], # 允許的版本'VERSION_PARAM': 'version' # URL中獲取值的key } setting.py from django.conf.urls import url, include from web.views import TestViewurlpatterns = [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 #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.versioning import NamespaceVersioningclass TestView(APIView):versioning_class = NamespaceVersioningdef get(self, request, *args, **kwargs):# 獲取版本print(request.version)# 獲取版本管理的類print(request.versioning_scheme)# 反向生成URLreverse_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(6)全局使用
REST_FRAMEWORK = {'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",'DEFAULT_VERSION': 'v1','ALLOWED_VERSIONS': ['v1', 'v2'],'VERSION_PARAM': 'version' } settings.py?
5.解析器(parser)
根據請求頭content-type選擇對應的解析器就請求體內容處理。
(1)進處理請求頭content-type為application/json的請求體
from django.conf.urls import url, include from web.views.s5_parser import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'), ] urls.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 JSONParserclass TestView(APIView):parser_classes = [JSONParser, ]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(2)僅處理請求頭content-type為application/x-www-form-urlencoded的請求體
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'), ] urls.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 FormParserclass 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(3)僅處理請求頭content-type為multipart/form-data的請求體
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'), ] urls.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 MultiPartParserclass 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 <!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(4)僅上傳文件
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'), ] urls.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 FileUploadParserclass 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 <!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(5)同時多個Parser
當同時使用多個parser時,rest framework會更具請求頭content-type自動進行比對,并使用對應parser。
from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'), ] urls.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, MultiPartParserclass 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(6)全局使用
REST_FRAMEWORK = {'DEFAULT_PARSER_CLASSES':['rest_framework.parsers.JSONParser''rest_framework.parsers.FormParser''rest_framework.parsers.MultiPartParser']} settings.py from django.conf.urls import url, include from web.views import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'), ] urls.py #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Responseclass 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.序列化
序列化用于對用戶請求數據進行驗證和數據進行序列化。
(1)自定義字段
from django.conf.urls import url, include from web.views.s6_serializers import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'), ] urls.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 modelsclass PasswordValidator(object):def __init__(self, base):self.base = basedef __call__(self, value):if value != self.base:message = 'This field must be %s.' % self.baseraise 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是當前字段對象passclass 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(2)基于Model自動生成字段
from django.conf.urls import url, include from web.views.s6_serializers import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'), ] urls.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 modelsclass 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.baseraise 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是當前字段對象passclass ModelUserSerializer(serializers.ModelSerializer):user = serializers.CharField(max_length=32)class Meta:model = models.UserInfofields = "__all__"# fields = ['user', 'pwd', 'ut']depth = 2extra_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(3)生成URL
from django.conf.urls import url, include from web.views.s6_serializers import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'),url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='detail'), ] urls.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 modelsclass 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.baseraise 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是當前字段對象passclass ModelUserSerializer(serializers.ModelSerializer):ut = serializers.HyperlinkedIdentityField(view_name='detail')class Meta:model = models.UserInfofields = "__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(4)自動生成URL
from django.conf.urls import url, include from web.views.s6_serializers import TestViewurlpatterns = [url(r'test/', TestView.as_view(), name='test'),url(r'detail/(?P<pk>\d+)/', TestView.as_view(), name='xxxx'), ] urls.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 modelsclass 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.baseraise 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是當前字段對象passclass ModelUserSerializer(serializers.HyperlinkedModelSerializer):ll = serializers.HyperlinkedIdentityField(view_name='xxxx')tt = serializers.CharField(required=False)class Meta:model = models.UserInfofields = "__all__"list_serializer_class = serializers.ListSerializerextra_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.分頁
(1)根據頁碼進行分頁
from django.conf.urls import url, include from rest_framework import routers from web.views import s9_paginationurlpatterns = [url(r'^test/', s9_pagination.UserViewSet.as_view()), ] urls.py #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework import serializers from .. import modelsfrom rest_framework.pagination import PageNumberPaginationclass StandardResultsSetPagination(PageNumberPagination):# 默認每頁顯示的數據條數page_size = 1# 獲取URL參數中設置的每頁顯示數據條數page_size_query_param = 'page_size'# 獲取URL參數中傳入的頁碼keypage_query_param = 'page'# 最大支持的每頁顯示的數據條數max_page_size = 1class UserSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__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(2)位置和個數進行分頁
from django.conf.urls import url, include from web.views import s9_paginationurlpatterns = [url(r'^test/', s9_pagination.UserViewSet.as_view()), ] urls.py #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework import serializers from .. import modelsfrom rest_framework.pagination import PageNumberPagination,LimitOffsetPaginationclass StandardResultsSetPagination(LimitOffsetPagination):# 默認每頁顯示的數據條數default_limit = 10# URL中傳入的顯示數據條數的參數limit_query_param = 'limit'# URL中傳入的數據位置的參數offset_query_param = 'offset'# 最大每頁顯得條數max_limit = Noneclass UserSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__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(3)游標分頁
from django.conf.urls import url, include from web.views import s9_paginationurlpatterns = [url(r'^test/', s9_pagination.UserViewSet.as_view()), ] urls.py #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework import serializers from .. import modelsfrom rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPaginationclass 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.UserInfofields = "__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.路由系統
(1)自定義路由
from django.conf.urls import url, include from web.views import s11_renderurlpatterns = [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 from rest_framework.views import APIView from rest_framework.response import Response from .. import modelsclass TestView(APIView):def get(self, request, *args, **kwargs):print(kwargs)print(self.renderer_classes)return Response('...') views.py(2)半自動路由
from django.conf.urls import url, include from web.views import s10_genericurlpatterns = [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 #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.viewsets import ModelViewSet from rest_framework import serializers from .. import modelsclass UserSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class UserViewSet(ModelViewSet):queryset = models.UserInfo.objects.all()serializer_class = UserSerializer views.py(3)全自動路由
from django.conf.urls import url, include from rest_framework import routers from web.views import s10_genericrouter = routers.DefaultRouter() router.register(r'users', s10_generic.UserViewSet)urlpatterns = [url(r'^', include(router.urls)), ] urls.py from rest_framework.viewsets import ModelViewSet from rest_framework import serializers from .. import modelsclass UserSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class UserViewSet(ModelViewSet):queryset = models.UserInfo.objects.all()serializer_class = UserSerializer views.py?
9.視圖
(1)GenericViewSet
from django.conf.urls import url, include from web.views.s7_viewset import TestViewurlpatterns = [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 #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework import viewsets from rest_framework.response import Responseclass TestView(viewsets.GenericViewSet):def list(self, request, *args, **kwargs):return Response('...')def add(self, request, *args, **kwargs):passdef delete(self, request, *args, **kwargs):passdef edit(self, request, *args, **kwargs):pass views.py(2)ModelViewSet(自定義URL)
from django.conf.urls import url, include from web.views import s10_genericurlpatterns = [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 #!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.viewsets import ModelViewSet from rest_framework import serializers from .. import modelsclass UserSerializer(serializers.ModelSerializer):class Meta:model = models.UserInfofields = "__all__"class UserViewSet(ModelViewSet):queryset = models.UserInfo.objects.all()serializer_class = UserSerializer views.py(3)ModelViewSet(rest framework路由)
from django.conf.urls import url, include from rest_framework import routers from app01 import viewsrouter = 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 from rest_framework import viewsets from rest_framework import serializersclass UserSerializer(serializers.HyperlinkedModelSerializer):class Meta:model = models.Userfields = ('url', 'username', 'email', 'groups')class GroupSerializer(serializers.HyperlinkedModelSerializer):class Meta:model = models.Groupfields = ('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 = UserSerializerclass 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
(1)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/?
(2)表格
訪問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/
(3)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/?
(4)自定義顯示模板
訪問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/
(5)瀏覽器格式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/?
注意:如果同時多個存在時,自動根據URL后綴來選擇渲染器。
?
轉載于:https://www.cnblogs.com/yangmingxianshen/p/8847178.html
總結
以上是生活随笔為你收集整理的Django Rest Framework(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql数据库中case when 的
- 下一篇: 51Nod 1043 幸运号码