drf認證、許可權、頻率、過濾和排序、全域性異常
阿新 • • 發佈:2021-07-06
drf路由
1.簡易版本
# 繼承modelviewmixin 手動配置路由,如下
path('booklogin',views.BookLogin.as_view({'get':'login'}))
檢視類
class BookLogin(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerial
# 派生方法
def login(self, request, *args, **kwargs):
return Response('登入功能')
2.檢視類中的派生方法自動生成路由
路由
from django.contrib import admin
from django.urls import path,include
from app01 import views
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('booklogin', views.BookLogin)
urlpatterns = [
path('admin/', admin.site.urls),
path('', include(router.urls)),
]
#生成的路由
^booklogin/$ [name='book-list']
^booklogin/login/$ [name='book-login']
^booklogin/(?P<pk>[^/.]+)/$ [name='book-detail']
# 如果檢視類中的引數 @action(methods=['GET', ], detail=True),得到的檢視結果如下
^booklogin/$ [name='book-list']
^booklogin/(?P<pk>[^/.]+)/$ [name='book-detail']
^booklogin/(?P<pk>[^/.]+)/login/$ [name='book-login']
檢視函式
from rest_frame.decorators import action
class BookLogin(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerial
de
# 加個action裝飾器
@action(methods=['GET', ], detail=False)
def login(self, request, *args, **kwargs):
return Response('登入功能')
drf認證
自己寫一個類繼承,BaseAuthentication,看原始碼得知需要重寫其中的authenticate方法
class BaseAuthentication:
"""
All authentication classes should extend BaseAuthentication.
"""
def authenticate(self, request):
"""
Authenticate the request and return a two-tuple of (user, token).
"""
raise NotImplementedError(".authenticate() must be overridden.")
自己寫一個認證類
class LoginAuth(BaseAuthentication):
# 重寫這個方法
def authenticate(self, request):
# 在這裡面寫上認證邏輯
if ... :
return
else:
raise AuthenticationFailed('認證失敗,重試')
然後在檢視類中使用
from rest_framework.decorators import action
from .myauth import LoginAuth
class BookLogin(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerial
# 將自己寫的認證類放入下面這個列表中
authentication_classes = [LoginAuth, ]
認證類的全域性使用和區域性使用
# 全域性使用,在專案的配置檔案中進行配置
# from app01.myauth import LoginAuth
# app01.myauth.LoginAuth # 謹慎防錯
REST_FRAMEWORK = {
#配置響應格式,預設有倆(json,瀏覽器的)
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
# 全域性使用寫得認證類
'DEFAULT_AUTHENTICATION_CLASSES':['app01.myauth.LoginAuth'],
}
區域性使用,見上邊那個就是
區域性禁用
當在全域性配置時,如果想使某一個不被認證,就可以區域性禁用,不使用認證
就是在區域性禁用的基礎上,使列表內為空
# 將自己寫的認證類放入下面這個列表中
authentication_classes = []
*******************************************************
from rest_framework.decorators import action
from .myauth import LoginAuth
class BookLogin(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerial
# 登入
@action(methods=['POST', ], detail=False)
def login(self, request, *args, **kwargs):
...
return Response()
認證類原始碼分析
首先記得是drf封裝了一個新的requset物件,重寫了as_view(),但是使用super().as_view(),又重新呼叫了父類的方法--》dispatch方法
# 基本流程
許可權
-
myauth.py
from rest_framework.permissions import BasePermission
# 寫一個類繼承BasePermission,重寫has_permission方法
class MyPermission(BasePermission):
def has_permission(self, request, view):
# 許可權相關邏輯
if request.user.role == 1:
return True
else:
return False
全域性使用和區域性使用
-
檢視類
# 區域性使用
from .myauth import LoginAuth, MyPermission
class BookLogin(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerial
# 在全域性中配置以後,將這個註釋掉
# authentication_classes = [LoginAuth, ]
# 許可權配置
permission_classes = [MyPermission, ]
-
全域性使用:專案的配置檔案中
'DEFAULT_PERMISSION_CLASSES': [
'app01.myauth.MyPermission',
]
補充
def update_or_cretae(self, default=None, **kwargs)
return obj, False
使用:
models.表名.objects.update_or_create(defaults={'xxx': xxxx}, xx=xx)
頻率
-
自定義頻率類
# 頻率
from rest_framework.throttling import SimpleRateThrottle
class MyThrottling(SimpleRateThrottle):
def get_cache_key(self, request, view):
# 返回什麼就限制什麼,一般可以是使用者id,IP地址等。。
# 返回None就不做限制
return
-
在檢視類中配置
from .myauth import LoginAuth, MyPermission, MyThrottling
class BookLogin(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerial
# 在全域性中配置以後,將這個註釋掉
# authentication_classes = [LoginAuth, ]
# 許可權配置
permission_classes = [MyPermission, ]
# 頻率
throttle_classes = [MyThrottling, ]
-
在配置檔案中配置
# 頻率限制配置資訊
'DEFAULT_THROTTLE_RATES':{
'ip_throttle': '3/m'
}
-
區域性使用
上述為區域性使用
-
全域性使用
# 還是在配置檔案中配置
'DEFAULT_THROTTLE_CLASSES': [
'app01.myauth.MyThrottling',
],
'DEFAULT_THROTTLE_RATES':{
'ip_throttle': '3/m',
}
過濾和排序
# 查詢所有才需要過濾和排序
-
在檢視類中進行配置
# 在檢視類中配置,最頂層的類至少是GenericAPIView
from rest_framework.filters import SearchFilter,OrderingFilter
class BookList(ModelViewSet, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerial
# 在檢視類中配置過濾
filter_backends = [SearchFilter, OrderingFilter]
# 過濾條件,欄位
search_fields = ['name',]
# 排序,欄位
ordering_fields = ['欄位']
-
篩選,要跟在url中
# 篩選
http://127.0.0.1:8000/booklist/?token=cacb18e4-09d1-4ec0-81c7-9ac46bf8d0a7&search=%E8%AE%BA%E8%AF%AD
-
過濾外掛
pip3 install django-fliter
-
使用
# 檢視類
from django_filter.rest_framework import DjangoFilterBackend
class xxx():
...
filter_backends = [DjangoFilterBackend, ]
filter_fields = ['欄位']
全域性異常
1 全域性統一捕獲異常,返回固定的格式 {code:999,msg:'未知錯誤'}
2 使用步驟
-寫一個函式
-在配置檔案中配置
# 寫函式
from rest_framework.views import exception_handler
from rest_framework.response import Response
def common_exception_handler(exc, context):
# 記錄日誌
print(context['request'].META.get('REMOTE_ADDR'))
response=exception_handler(exc, context)
if response: # 處理了drf的異常
data = {'code': 999, 'msg': '錯誤','detail':response.data}
return Response(data)
else: # 不知道的異常
data = {'code':999,'msg':'未知錯誤'}
return Response(data)
# 配置檔案配置
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'app01.utils.common_exception_handler',
}
拓展
1 看這個原始碼
from django.contrib.sessions.middleware import SessionMiddleware
2 request.session原始碼
django.contrib.sessions.backends.db.SessionStore
3 內網穿透