DRF 框架
restful 規範
- 定義
- 軟體的一種架構風格,透過HTTP協議進行資料互動。核心思想:將系統中的資源(網頁,文字,資料等)表示為統一的資源識別符號(URL)
- 使用:POST,GET,PUT,DELETE等HTTP請求方法,對資源操作
- 特點
- 使用HTTP方法表示資源操作型別。GET 獲取,POST建立,PUT更新,DELETE刪除
- 使用URL表示資源:URL儘可能多的反應資源的層次結構和名稱
- 使用狀態碼操作:2xx,4xx,5xx等
- 使用JSON/XML作為資料傳輸格式。保證資料的可讀性和可擴充套件性
- 無狀態:restful系統是無狀態的,每個請求是獨立的,不依賴之前的請求和會話
- 快取友好性:restful支援快取,提高效能和減少服務資源負載
DRF 元件認證過程
1. 使用者傳送請求到 API端點(服務,伺服器上的服務)
2. API檢查請求頭的Authorization欄位,來確定請求是否經過認證
3. 如果請求未經過認證,則返回401,提示使用者進行認證操作
4. 如果請求經過認證,則要求API檢查請求的許可權,確定使用者是否具有執行該操作的許可權
5. 如果使用者執行該做操沒有許可權,則返回403,提示使用者沒有許可權執行該操作
6. 如果使用者具有該操作的許可權,則執行API邏輯,並返回響應結果
7. 認證方式:基本認證,令牌認證,JSON WEB Token認證等
DRF 元件中的許可權認證
- 檢視級許可權 ,檢視中新增 permission_classes 屬性指定許可權
from rest_framework.permissions import IsAuthenticated
class MyView(APIView):
permission_classes = (IsAuthenticated,)
- 路由級許可權,路由中新增 permission_classes 屬性指定許可權
from rest_framework.permissions import IsAuthenticated
router = DefaultRouter()
router.register(r'users', UserViewSet, base_name='user')
router.route('list', permission_classes=(IsAuthenticated,))
- 自定義許可權。
from rest_framework.permissions import BasePermission
class MyPermission(BasePermission):
def has_permission(self, request, view):
# 自定義許可權邏輯
return True
class MyView(APIView):
permission_classes = (MyPermission,)
DRF 元件中的節流實現方式
- 頻率限制
- 使用者在一定時間可以傳送的請求數量。如:限制使用者每分鐘只能傳送10個請求。
- 實現:透過cache模組,DRF提供 _throttled_cache 中介軟體,來實現頻率限制
- 程式碼如下:
from django.core.cache import cache
from django.middleware.cache import ThrottledCache
# 建立一個 ThrottledCache 例項
throttled_cache = ThrottledCache(timeout=60, key_prefix='my_cache')
# 將 ThrottledCache 例項新增到 DRF 的中介軟體列表中
MIDDLEWARE = [
xxxxx,
xxxxx,
'throttled_cache.middleware.ThrottledCacheMiddleware',
]
- 請求限制
- 指某個IP在一定時間內傳送的請求數量。如:限制43.10.10.22 ip 每小時只能傳送1000個請求
- 實現:使用django的request模組,DRF 提供 _throttled_request 中介軟體來限制
- 程式碼:
# 在檢視中使用 ThrottledCache 中介軟體
from rest_framework.response import JsonResponse
def my_view(request):
# 檢查請求是否被快取
if not throttled_cache.get_cache_key(request):
return JsonResponse({'error': '請求太頻繁,請稍後再試。'}, status=429)
# 處理請求
#...
# 快取請求
throttled_cache.set_cache_key(request)
# 返回響應
return JsonResponse({'result': '請求處理成功。'})
什麼是JWT?
-
一般用於前後端分離專案。 用於做使用者認證
-
jwt實現原理
- 使用者登陸成功後,返回一段字串(token)
- token 是由 三段組成
- 第一段: 型別 和 演算法 資訊
- 第二段: 使用者資訊 + 超時時間
- 第三段: hs256加密 (拼接前兩段資訊)
- 在使用 base64url 進行二次加密。(處理&和特殊字元)
- 後端驗證token
- token 超時驗證
- token的合法性驗證
-
jwt的優勢
- 服務端不儲存token資訊,只在客戶瀏覽器儲存。 後端只負責校驗
- 內部整合超時時間,後端可以根據時間校驗token是否超時
- 使用者不可修改token,修改後token驗證失敗
Django 編寫試圖方式
- 第一種:APIView
- 自己編寫CRUD檢視,編寫分頁等
- 第二種:ListAPIView,CreateAPIView等
- 實現認證,分頁,CRUD等
- 第三種:GenericViewSet,ListModelMixin,CreateModelMixin等
- 整合所有的功能,需要在路由指定方法
- 第四種 viewsetes.ModelViewSet 實現上面所有功能
DRF 回顧
- 裝飾器
def wrapper(func):
def inner(*args,**kwargs):
ret = func(*args,**kwargs)
return ret
return inner
# 裝飾器1
@wrapper
def index(f1):
pass
# 裝飾器2
index = wrapper(index)
-
django csrf_exempt 免認證
from django.views.decorators.csrf import csrf_exempt from django.shortcuts import HttpResponse @csrf_exempt def index(request): return HttpResponse('...') # index = csrf_exempt(index) urlpatterns = [ url(r'^index/$',index), ]
urlpatterns = [ url(r'^login/$',account.LoginView.as_view()), ] class APIView(View): @classmethod def as_view(cls, **initkwargs): view = super().as_view(**initkwargs) view.cls = cls view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated, # all other authentication is CSRF exempt. return csrf_exempt(view)
-
物件導向中 基於 異常+繼承 實現約束
class BaseVersioning: def determine_version(self, request, *args, **kwargs): raise NotImplementedError("must be implemented") class URLPathVersioning(BaseVersioning): def determine_version(self, request, *args, **kwargs): version = kwargs.get(self.version_param, self.default_version) if version is None: version = self.default_version if not self.is_allowed_version(version): raise exceptions.NotFound(self.invalid_version_message) return version
-
物件導向的封裝
class Foo(object): def __init__(self,name,age): self.name = name self.age = age obj = Foo('汪洋',18)
class APIView(View): def dispatch(self, request, *args, **kwargs): self.args = args self.kwargs = kwargs request = self.initialize_request(request, *args, **kwargs) self.request = request ... def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) return Request( request, parsers=self.get_parsers(), authenticators=self.get_authenticators(), # [MyAuthentication(),] negotiator=self.get_content_negotiator(), parser_context=parser_context )
-
物件導向的繼承
class View(object): pass class APIView(View): def dispatch(self): method = getattr(self,'get') method() class GenericAPIView(APIView): serilizer_class = None def get_seriliser_class(self): return self.serilizer_class class ListModelMixin(object): def get(self): ser_class = self.get_seriliser_class() print(ser_class) class ListAPIView(ListModelMixin,GenericAPIView): pass class UserInfoView(ListAPIView): pass view = UserInfoView() view.dispatch()
class View(object): pass class APIView(View): def dispatch(self): method = getattr(self,'get') method() class GenericAPIView(APIView): serilizer_class = None def get_seriliser_class(self): return self.serilizer_class class ListModelMixin(object): def get(self): ser_class = self.get_seriliser_class() print(ser_class) class ListAPIView(ListModelMixin,GenericAPIView): pass class UserInfoView(ListAPIView): serilizer_class = "汪洋" view = UserInfoView() view.dispatch()
class View(object): pass class APIView(View): def dispatch(self): method = getattr(self,'get') method() class GenericAPIView(APIView): serilizer_class = None def get_seriliser_class(self): return self.serilizer_class class ListModelMixin(object): def get(self): ser_class = self.get_seriliser_class() print(ser_class) class ListAPIView(ListModelMixin,GenericAPIView): pass class UserInfoView(ListAPIView): def get_seriliser_class(self): return "咩咩" view = UserInfoView() view.dispatch()
-
反射
class View(object): def dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn't exist, # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list. if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs)
-
傳送ajax請求
$.ajax({ url:"地址", type:"GET", data:{}, success:function(e){ console.log(e) } })
-
瀏覽器具有 同源策略 跨域如何產生的? 導致 ajax請求+跨域 存在 無法獲取資料
- 簡單請求,傳送一次請求
- 複雜請求,先做 options 請求預檢,在傳送真正的請求
IP 埠 協議
-
如何解決 跨域
CORS 本質:設定響應頭
-
常見的HTTP請求方法
Get,POST,PUT,OPTIONS,PATCH,DELETE ...
-
HTTP 請求頭。Content-Type 請求頭
- application/x-www-form-urlencoded django 的 request.POST 和 request.body 中均有資料 - appliction/json django 的 request.POST 沒有值,request.body 有資料
-
django 的 fbv 和 cbv 都能遵循 restful 規範介面
-
django rest framework 框架 實現 restful api 開發
- 免除 csrf 認證 - 分頁 - 許可權 - 檢視(APIView,ListApiView,ListModelMixin...) 類的繼承 - 序列化 serializer - 版本 Version - 節流 - 解析器 - 篩選器 - 認證 - 渲染器
-
簡述 drf 中的認證流程
-
簡述drf 中的節流實現原理, 匿名使用者 和 非匿名使用者 實現頻率限制
-
GenericAPIView 檢視類
- 提供了一些規則 - serilizer_class = None - lookup_field = 'pk' - queryset = None - filter_backends = - get_queryset(self) - get_object(self) - get_serializer_class(self): return self.
-
jwt的優勢
-
序列化時,many=True 和 many = False 的區別
-
django 的 F 查詢
-
django 的 獲取空的queryset
models.XXX.objects.all().none()
-
應用 DRF 中的功能開發
***** 非常重要 檢視: 序列化: 解析器 request.data / request.query_params 渲染器:Response **** request 物件封裝 版本處理 分頁處理 *** 認證 許可權 節流 - 基於 APIView 實現 呼啦圈 專案 - 基於 GenericView,ListModelMixin 實現呼啦圈 專案
-
GenericAPIView檢視類的作用?
他提供了一些規則,例如: class GenericAPIView(APIView): serializer_class = None queryset = None lookup_field = 'pk' filter_backends = api_settings.DEFAULT_FILTER_BACKENDS pagination_class = api_settings.DEFAULT_PAGINATION_CLASS def get_queryset(self): return self.queryset def get_serializer_class(self): return self.serializer_class def filter_queryset(self, queryset): for backend in list(self.filter_backends): queryset = backend().filter_queryset(self.request, queryset, self) return queryset @property def paginator(self): if not hasattr(self, '_paginator'): if self.pagination_class is None: self._paginator = None else: self._paginator = self.pagination_class() return self._paginator 他相當於提供了一些規則,建議子類中使用固定的方式獲取資料,例如: class ArticleView(GenericAPIView): queryset = models.User.objects.all() def get(self,request,*args,**kwargs): query = self.get_queryset() 我們可以自己繼承GenericAPIView來實現具體操作,但是一般不會,因為更加麻煩。 而GenericAPIView主要是提供給drf內部的 ListAPIView、Create.... class ListModelMixin: def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) class ListAPIView(mixins.ListModelMixin,GenericAPIView): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) class MyView(ListAPIView): queryset = xxxx ser...
總結:GenericAPIView主要為drf內部幫助我們提供增刪改查的類LIstAPIView、CreateAPIView、UpdateAPIView、提供了執行流程和功能,我們在使用drf內建類做CURD時,就可以透過自定義 靜態欄位(類變數)或重寫方法(get_queryset、get_serializer_class)來進行更高階的定製。
-
序列化時many=True和many=False的區別?
在 Django Rest Framework(DRF)中,序列化時 many=True 和 many=False 的區別在於它們指定了序列化的物件是單個例項還是一個集合。 many=True 表示序列化的是一個集合(列表、可迭代物件等)。這意味著序列化器將處理多個物件,並返回一個包含多個序列化例項的陣列或列表。 many=False 表示序列化的是單個例項。序列化器將處理單個物件,並返回該單個序列化例項。 以下是一些主要的區別: 返回格式:many=True 返回列表,many=False 返回單個物件。 資料處理:在序列化多個物件時,many=True 會逐個處理每個物件。 檢視響應:根據 many 的設定,檢視可能會返回不同的 HTTP 狀態碼和響應結構。 序列化邏輯:可能會有不同的邏輯來處理單個例項或集合。 透過設定 many 引數,DRF 可以靈活地處理單個物件和物件集合的序列化需求,以便與客戶端進行有效的資料互動。