因爲筆者水平有限,學習技術官方文檔永遠是首先被推薦的,推薦來自Django REST framework官網的快速教程html
models:python
後面的代碼將基於這幾個表來作操做web
1 class BookDetailView(APIView): 2 """ 3 針對單條數據的序列化 4 """ 5 6 def get(self,request,id): 7 8 book=Book.objects.filter(pk=id).first() 9 bs=BookModelSerializers(book,context={'request': request}) 10 return Response(bs.data) 11 12 def put(self,request,id): 13 book=Book.objects.filter(pk=id).first() 14 bs=BookModelSerializers(book,data=request.data) 15 if bs.is_valid(): 16 bs.save() 17 return Response(bs.data) 18 else: 19 return Response(bs.errors) 20 21 def delete(self,request,id): 22 Book.objects.filter(pk=id).delete() 23 24 return Response()
序列化的方法:django
方法一: 硬傳值json
class PublishView(View): def get(self,request): # 方式一: publish_list = list(Publish.objects.all().values("name","email")) # {'name': '蘋果出版社', 'email': '123@qq.com'}{'name': '橘子出版社', 'email': '456@qq.com'} return HttpResponse(publish_list)
方法二: model_to_dict(obj)api
1 class PublishView(View): 2 def get(self,request): 3 from django.forms.models import model_to_dict 4 publish_list = Publish.objects.all() 5 temp = [] 6 for obj in publish_list: 7 # temp.append({ 8 # "name":obj.name, 9 # "email":obj.email 10 # }) 11 temp.append(model_to_dict(obj)) 12 print(temp, type(temp)) 13 # [{'name': '蘋果出版社', 'email': '123@qq.com'}, {'name': '橘子出版社', 'email': '456@qq.com'}] <class 'list'> 14 # [{'id': 1, 'name': '蘋果出版社', 'email': '123@qq.com'}, {'id': 2, 'name': '橘子出版社', 'email': '456@qq.com'}] <class 'list'> 15 16 return HttpResponse(temp)
方法三: serializers.serialize("json",publish_list)緩存
class PublishView(View): def get(self,request): from django.core import serializers publish_list = Publish.objects.all() ret = serializers.serialize("json",publish_list) """ [ { "model": "app01.publish", "pk": 1, "fields": { "name": "蘋果出版社", "email": "123@qq.com" } }, { "model": "app01.publish", "pk": 2, "fields": { "name": "橘子出版社", "email": "456@qq.com" } } ] """ return HttpResponse(ret)
方法四:rest_framework serializersapp
1 from rest_framework import serializers 2 3 class PublishSerializers(serializers.Serializer): 4 name = serializers.CharField() 5 email = serializers.EmailField() 6 7 8 class PublishView(View): 9 def get(self,request): 10 # 方式四(推薦) 11 publish_list = Publish.objects.all() 12 ret = PublishSerializers(publish_list, many=True) # queryset 13 # print(ret.data) 14 # print(type(ret.data)) 15 # [OrderedDict([('name', '蘋果出版社'), ('email', '123@qq.com')]), 16 # OrderedDict([('name', '橘子出版社'), ('email', '456@qq.com')])] 17 # <class 'rest_framework.utils.serializer_helpers.ReturnList'> 18 """ 19 >>>dict([("name","橘子出版社"),("email","456@qq.com")]) 20 {'name': '橘子出版社', 'email': '456@qq.com'} 21 """ 22 23 return HttpResponse(ret.data)
終結者:ModelSerializeride
咱們的 PublishSerializers 類中重複了不少包含在Publish模型類(model)中的信息。若是能保證咱們的代碼整潔,那就更好了。post
就像Django提供了Form
類和ModelForm
類同樣,REST framework包括Serializer
類和ModelSerializer
類。
下面咱們換一個稍微複雜的有外鍵的模型來進行演示:
1 class BookModelSerializers(serializers.ModelSerializer): 2 class Meta: 3 model = Book 4 fields = "__all__" 5 6 #publish=serializers.CharField(source="publish.pk") 7 publish=serializers.HyperlinkedIdentityField( 8 view_name="detailpublish", 9 lookup_field="publish_id", 10 lookup_url_kwarg="pk" 11 ) 12 13 14 class BookView(APIView): 15 def get(self,request): 16 book_list=Book.objects.all() 17 bs=BookModelSerializers(book_list,many=True,context={'request': request}) 18 return Response(bs.data) 19 def post(self,request): 20 # post請求的數據 21 bs=BookModelSerializers(data=request.data) 22 if bs.is_valid(): 23 print(bs.validated_data) 24 bs.save()# create方法 25 return Response(bs.data) 26 else: 27 return Response(bs.errors) 28 29 class BookDetailView(APIView): 30 """ 31 針對單條數據的序列化 32 """ 33 34 def get(self,request,id): 35 36 book=Book.objects.filter(pk=id).first() 37 bs=BookModelSerializers(book,context={'request': request}) 38 return Response(bs.data) 39 40 def put(self,request,id): 41 book=Book.objects.filter(pk=id).first() 42 bs=BookModelSerializers(book,data=request.data) 43 if bs.is_valid(): 44 bs.save() 45 return Response(bs.data) 46 else: 47 return Response(bs.errors) 48 49 def delete(self,request,id): 50 Book.objects.filter(pk=id).delete() 51 52 return Response()
在CBV的基礎上,視圖類在繼承了REST framework的 APIVIEW 後產生了新的調用方法
request的增強:
1 原生request支持的操做 2 print("POST",request.POST) 3 print("body",request.body) 4 # print(request) 5 print(type(request)) 6 from django.core.handlers.wsgi import WSGIRequest 7 新的request支持的操做 8 print("request.data",request.data) 9 print("request.data type",type(request.data))
a. 用戶url傳入的token認證
from django.conf.urls import url, include from web.viewsimport TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
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請求,響應內容')
b. 請求頭認證
from django.conf.urls import url, include from web.viewsimport TestView urlpatterns = [ 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 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. 多個認證規則
from django.conf.urls import url, include from web.views.s2_auth import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
#!/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請求,響應內容')
d. 認證和權限
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
#!/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. 全局使用
上述操做中均是對單獨視圖進行特殊配置,若是想要對全局進行配置,則須要再配置文件中寫入便可。
REST_FRAMEWORK = { 'UNAUTHENTICATED_USER': None, 'UNAUTHENTICATED_TOKEN': None, "DEFAULT_AUTHENTICATION_CLASSES": [ "web.utils.TestAuthentication", ], "DEFAULT_PERMISSION_CLASSES": [ "web.utils.TestPermission", ], }
from django.conf.urls import url, include from web.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
#!/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
a. 基於用戶IP限制訪問頻率
b. 基於用戶IP顯示訪問頻率(利於Django緩存)
c. view中限制請求頻率
d. 匿名時用IP限制+登陸時用Token限制
e. 全局使用
根據請求頭 content-type 選擇對應的解析器就請求體內容進行處理。
a. 僅處理請求頭content-type爲application/json的請求體
b. 僅處理請求頭content-type爲application/x-www-form-urlencoded 的請求體
c. 僅處理請求頭content-type爲multipart/form-data的請求體
d. 僅上傳文件
e. 同時多個Parser
當同時使用多個parser時,rest framework會根據請求頭content-type自動進行比對,並使用對應parser
f. 全局使用
注意:個別特殊的值能夠經過Django的request對象 request._request 來進行獲取
a. 根據頁碼進行分頁
b. 位置和個數進行分頁
c. 遊標分頁
a. 自定義路由
b. 半自動路由
c. 全自動路由
a. GenericViewSet
b. ModelViewSet(自定義URL)
c. ModelViewSet(rest framework路由)
武佩奇:https://www.cnblogs.com/wupeiqi/articles/7805382.htmlYUAN先生: https://www.cnblogs.com/yuanchenqi/articles/8719520.html