FBV 和 CBV前端
CBV 經過函數調用方法
FBV 經過類調用方法
其本質上都是 CBV
可是 FBV 內部封裝了關於 method 的方法,因爲基本上都是前端的請求,全部像GET,POST等方法用的頻繁,
而CBV將這些方法封裝了起來,使得開發時更便捷了許多,因此CBV更適合寫接口
###### 標準的 ######
2.1 fbv方式請求的過程
用戶發送url請求,Django會依次遍歷路由映射表中的全部記錄,一旦路由映射表其中的一條匹配成功了,
就執行視圖函數中對應的函數名,這是fbv的執行流程
2.2 cbv方式請求的過程
當服務端使用cbv模式的時候,用戶發給服務端的請求包含url和method,這兩個信息都是字符串類型
服務端經過路由映射表匹配成功後會自動去找dispatch方法,而後Django會經過dispatch反射的方式找到類中對應的方法並執行
類中的方法執行完畢以後,會把客戶端想要的數據返回給dispatch方法,由dispatch方法把數據返回經客戶端
數據庫
一:下載django
pip install djangorestframewrok
二:Viewsjson
# restframework 經常使用的類 from rest_framework.views import APIView from rest_framework.generics import GenericAPIView from rest_framework.viewsets import GenericViewSet from rest_framework.viewsets import ModelViewSet from rest_framework.response import Response
寫法1:session
-- from rest_framework import serializers (1)和 models 表中的字段對應 (使用模塊:serializers.Serializer) (2)所有字段直接寫(使用模塊:serializers.ModelSerializer) class Meta: model = models.Book fields = '__all__' (3)使用時須要調用 BookModelSerializers(queryset/data,many=True/False) 注:當須要返回一個 queryset 的時候必須加 many=True 這個參數,單條數據則不用 -- ----------Url---------- from app01 import views re_path('book/$',views.BookView.as_view()) ----------View---------- from rest_framework import serializers class BookModelSerializers(serializers.ModelSerializer): title = serializers.CharField() price = serializers.CharField() publish = serializers.CharField() from rest_framework.views import APIView from rest_framework.views import Response # 更新操做: def put(self,request,pk): shop = models.Shop.objects.filter(pk=pk).first() bs = ShopSerializers(shop,data=request.data) if bs.is_valid(): # 判斷數據是否有誤 print('bs: ',bs) bs.save() # 至關於調用了 updata方法 return Response(bs.data) # 返回 數據 else: return Response(bs.errors) # 添加操做: ps = PublishSerializers(data=request.data) if ps.is_valid(): ps.save() # create # 查詢操做: class BookView(APIView): def get(self,request): book_list = models.Book.objects.all() serializers = BookModelSerializers(book_list,many=True) return Response(serializers.data) # 刪除操做: def delete(self,request,pk): models.Shop.objects.filter(pk=pk).delete() return Response()
寫法2:app
-- (a) (1)mixins 模塊中有 List,Create,Put...方法能夠直接使用 (2)generics 主要做用仍是調用 APIView 中的 -- ----------Url---------- from app01 import views re_path('book/$',views.BookView.as_view()) ----------View (a)---------- from rest_framework import mixins from rest_framework import generics from rest_framework import serializers from rest_framework import serializers class BookModelSerializers(serializers.ModelSerializer): title = serializers.CharField() price = serializers.CharField() publish = serializers.CharField() class AuthorView(mixins.ListModelMixin,generics.GenericAPIView): queryset = models.Author.objects.all() # 必須有的參數 :queryset serializer_class = AuthorModelSerializers # 必須有的參數 :serializer_class def get(self,request,*args,**kwargs): return self.list(request,*args,**kwargs) -- (b) (1)繼承 generics.RetrieveUpdateDestroyAPIView 將上面的 mixins generics 所有封裝成了一個模塊 -- ----------View (b)---------- 比上面簡單一點 class UserView(generics.RetrieveUpdateDestroyAPIView): queryset = models.User.objects.all() serializer_class = UserModelSerializers
寫法三:dom
-- (1) as_view({參數}) 中傳的參數是必須的,參數的名稱仍是固定的, 可根據需求來限定哪一個url配定哪一個參數 (2) view 中 的變量名也是固定的,不能改變, 當執行到某個父類的方法的時候,就會須要這兩個參數 queryset -- queryset serializer_class -- ----------Url---------- from app01 import views re_path('book/$', views.Book.as_view({'get': 'list', 'post': 'create'})), re_path('book/(?P<pk>\d+)/$', views.Book.as_view({'get': 'retrieve', 'put': 'update','delete':'destroy'})), ----------View---------- from rest_framework import viewsets class Book(viewsets.ModelViewSet): queryset = models.Book.objects.all() serializer_class = BookModelSerializers
四:認證組件ide
---------- View(局部認證) ---------- -- (1) BaseAuthentication 模塊中 有倆個方法(authenticate , authenticate_header) 注:這倆個方法也是固定名字,兩個必須寫上,一個都不能少,不然報錯 ! 模塊中這兩個方法都是返回空的,可是執行的時候當前函數就將 兩個方法覆蓋了,也就是少些一個 authenticate_header (2) 建立一個 返回 隨機字符的 token (3) update_or_create -- 若是有就更新,若是沒有就建立 -- # 認證 組件 from rest_framework import exceptions from rest_framework.authentication import BaseAuthentication from app01 import models class TokenAuth(BaseAuthentication): # 這個方法直接寫在一個文件中 def authenticate(self,request): token = request.GET.get('token') # 獲取 token token_obj = models.Token.objects.filter(token=token).first() # 驗證 token 是否匹配 if not token_obj: raise exceptions.AuthenticationFailed('驗證失敗') else: return token_obj.user.name,token_obj.token # 返回一個 登錄校驗判斷 的隨機字符串 def get_random_str(user): import hashlib,time ctime = str(time.time()) # 當前時間字符串 md5 = hashlib.md5(bytes(user,encoding='utf8')) # md5 加密,加鹽 md5.update(bytes(ctime,encoding='utf8')) # 將字符串進行拼接 #md5.digest() 二進制 #md5.hexdigest() 十六進制 return md5.hexdigest() # 返回一個 十六進制 的加密隨機字符 # 登錄驗證 class LoginView(APIView): authentication_classes = [TokenAuth] def post(self,request): name = request.data.get('name') # 獲取用戶名 pwd = request.data.get('pwd') # 獲取密碼 user = models.User.objects.filter(name=name,pwd=pwd).first() # 數據庫校驗 res = {'code':0,'msg':None} if user: random_str = get_random_str(user.name) token = models.Token.objects.update_or_create(user=user,defaults={'token':random_str}) # 在數據庫生成 token res['token'] = random_str res['code'] = 1 res['msg'] = '驗證成功' else: res['msg'] = '驗證失敗' import json return Response(json.dumps(res)) ---------- View(全局認證) ---------- (1) settings 中配置 認證組件位置: # 全局認證組件 REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": ["app01.utils.TokenAuth",] } (2) 這樣就不用寫 authentication_classes = [TokenAuth] (3) 若是哪一個方法不須要認證的話 只須要 authentication_classes = [] 將列表設爲空
五:權限組件函數
# 權限組件 class SvipPermission(object): # 這個方法直接寫在一個文件中 message = "只有超級用戶才能訪問" def has_permission(self,request,view): username = request.user user_type = models.User.objects.filter(name=username).first().user_type if user_type == 3: return True # 返回True 則驗證經過 else: return False # 返回False 則驗證不經過
# 只需類下面添加
permission_classes = [SvipPermission] # 權限組件 -- 局部
# 全局認證
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES":['app01.utils.SvipPermission'], # 全局權限組件
}
六:解析器 (用於將解析字符格式)post
from rest_framework.parsers import JSONParser,FormParser parser_classes = [JSONParser, FormParser] # 局部 (用於將解析字符格式)
七:頻率組件:
- 自定義:
# 定義一個頻率認證類 - 以後在視圖配置 import time from rest_framework.throttling import BaseThrottle class MyThrottle(BaseThrottle): visited_record = {} def __init__(self): self.history = None def allow_request(self, request, my_cbv): # 這個my_cbv是源碼中傳的咱們的視圖類,這裏咱們也要傳進去 # print(self.get_ident(request)) # 能夠獲取本次請求的ip ip = request.META.get("REMOTE_ADDR") if ip not in self.visited_record: self.visited_record[ip] = [] current_time = time.time() history = self.visited_record[ip] self.history = history print(history) while history and current_time - history[-1] > 60: # 把大於60秒的時間都刪掉 history.pop() if len(history) > 2: # 第三次訪問,列表中只有2個值,也知足條件 return False history.insert(0, current_time) return True def wait(self): """ 用於返回還剩多少時間訪問; 本次訪問時間:9:50:55 [09:50:30, 09:50:20, 09:50:10] 剩餘 60 - (9:50:55 - 09:50:10)秒才能訪問 :return: """ c_time = time.time() return 60 - (c_time - self.history[-1]) #### 局部使用 #### from rest_framework import generics from rest_framework import mixins from app01.utils.frequency import MyThrottle class ListView(generics.GenericAPIView, mixins.ListModelMixin, mixins.CreateModelMixin): throttle_classes = [MyThrottle] def get(self, request, *args, **kwargs): return Response('ok') #### 全局使用 #### REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': ( 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ), 'DEFAULT_THROTTLE_CLASSES': ( 'app01.utils.frequency.MyThrottle', ), }
- 內置
#### 定義類 #### from rest_framework.throttling import SimpleRateThrottle class MyThrottle(SimpleRateThrottle): scope = "visit_rate" # 這個值決定了在配置時使用那個變量描述限制的頻率 def get_cache_key(self, request, view): # 這個方法也是必需要有 return self.get_ident(request) #### 只能在全局使用 #### REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': ( 'app01.utils.throttle_class.MyThrottle', ), "DEFAULT_THROTTLE_RATES": { "visit_rate": "10/m", # 這個參數就是頻率類中定義的那個參數scope, 其中第一個數字10表示10次,後面的m表示一分鐘,還有s,一秒, h, 一小時, d, 一天 } }
八:分頁器 -- 用於 restframework 內置的調試頁面
# 要使用 restframework 自帶的調試數據網頁 須要在 settings 中配置
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config',
'rest_framework', # 配置 restframework 組件
]
# 分頁器 from rest_framework.pagination import PageNumberPagination class BookPageNumberPagination(PageNumberPagination): page_size = 1 # 每頁顯示個數 page_query_param = 'page' page_size_query_param = 'size' # 修改當前頁顯示個數 #max_page_size = 2 # 每頁顯示個數限制 class BookView(APIView): def get(self,request): book_list = models.Book.objects.all() # 分頁器 pnp = BookPageNumberPagination() book_page = pnp.paginate_queryset(book_list,request,self) bs = BookModelSerializers(book_page,many=True,context={'request': request}) return Response(bs.data)