1. 程式人生 > 其它 >序列化與反序列化及初始drf

序列化與反序列化及初始drf

內容回顧

# 前後端開發模式
	-混合開發(前後端不分離)--》bbs---》頁面渲染是使用模板語法(dtl,jsp-->模板語法,php)-->後端執行-->把頁面渲染成純粹的html,css,js---》直接返回給前端---》瀏覽器中展示
  	-專案前端用php寫的,後端用python寫的---》嚴重錯誤
    -看到過在html中寫php語法--》在後端執行,等同於 dtl
    
    -對後端壓力比較大---》每次都要在後端渲染完成
    -後端人員需要寫前端東西
    -考你一個問題:寫在js中 var name ='{{name}}'
  -前後端分離
  	-頁面渲染前端完成---->js語法--》js的dom操作---》jq就是js的一個庫
    -前端專門寫前端---》html,css,js
    -後端專門寫後端--->java,python,go....
    -前端的形式可以是:PC端瀏覽器,小程式,app---》前後端互動使用json格式
    
  	
    
# API介面
	-前後端互動的媒介
  -咱們自己寫的一些後端介面
  -第三方服務對外提供的一些介面----》騰訊傳送簡訊---》使用了第三方的API介面
  -http地址
  
# 後端人員要測試介面---》不能只用瀏覽器---》瀏覽器只能傳送get請求(除非用ajax)--》postman
	-模擬傳送http請求--》指定請求方式,請求地址,請求引數,請求體。。。
  
  -http協議:
    請求協議:請求首行(有哪些東西),請求頭(常見請求頭),請求體(三種編碼格式:urlencoded,formdata,json)
    響應協議:響應首行(狀態碼),響應頭(cookie),響應體(在瀏覽器中看到的,就是響應體)
    
    
    
# restful規範
	-規範前後端互動api介面
  -10條---》不同公司有公司自己的一些自由規範
  	-https
    -api
    -v1
    -都是用名詞,可以複數
    -請求方法決定具體操作:get獲取資料,delete刪除資料
    -請求地址中帶過濾  ?name=xx
    -返回中帶狀態碼  http,自定製狀態碼
    -返回中帶錯誤資訊   msg  err
    -返回資料中帶連線
    -返回符合規範:獲取所有資料返回列表,單個數據字典,新增返回新增完的,刪除返回空文件

內容概要

  • 序列化與反序列化
  • drf介紹和快速使用
  • cbv原始碼流程分析 (瞭解)
  • drf之APIView和Request物件分析(瞭解)

1 序列化和反序列化

api介面開發,最核心最常見的一個過程就是序列化,所謂序列化就是把資料轉換格式,序列化可以分兩個階段:

# 序列化: 把我們語言識別的資料轉換成指定的格式提供給別人。
					字典,列表,物件------》json/xml/prop,massagepack--->提供給別人(前端或其他服務)

# 反序列化:把別人提供的資料轉換/還原成我們需要的格式


我們在django中獲取到的資料預設是模型物件(qs物件),但是模型物件資料無法直接提供給前端或別的平臺使用,所以我們需要把資料進行序列化,變成字串或者json資料,提供給別人----》序列化過程

前端傳入到後臺的資料---》json格式字串---》後端存到資料庫中,需要轉成python中的物件---》把json格式字串轉成python物件存到資料庫的過程稱為反序列化

2 drf介紹和快速使用

# 原生django,不使用任何其他模組,也可以寫出符合resful規範的介面---》寫起來麻煩一些
# 查詢所有圖書
	地址:127.0.0.1:8080/books
  路由:path('/books',views.books)
  檢視函式中:通過orm查出所有圖書(qs)--->序列化(for迴圈自己拼成列表套字典[{name:西遊記,price:99},{name:紅樓夢,price:99}])---->JsonResponse返回給前端
  
  
# drf是django的一個app--》幫助咱們快速在django上寫符合restful規範的介面

# 安裝:
	pip3 install djangorestframework
  注意:django版本 4.x     一般用升級到3.x  或者 2.x
  drf的最新版本最低支援django 3.x以上---》出一個小問題---》裝django 2.x---》當你pip3 install的時候,由於低於2.2不支援最新的drf---》把你老版本的django解除安裝---》給你裝上最新版---》原來寫的django專案可能有問題,執行不了
  
  2.2一下--->drf降降版本
  3.x---->drf使用最新
  
Python (3.6, 3.7, 3.8, 3.9, 3.10)
Django (2.2, 3.0, 3.1, 3.2, 4.0)

2.1 快速使用

# 針對於一個表,需要寫那些介面---》5個--》以後看到的所有介面都是這5個的變形
	-查詢所有---》get->http://127.0.0.1:8000/books/
  -查詢一個---》get->http://127.0.0.1:8000/books/1/
  -新增一個---》post->http://127.0.0.1:8000/books/ body中帶資料
  -修改-----》put,patch--->實際編碼中,基本都用put
  	http://127.0.0.1:8000/books/1/ body體中傳入修改的資料
  -刪除一個---》delete-->http://127.0.0.1:8000/books/1/
  
# 登陸介面---》本質其實是查詢一個

# 註冊介面----》本質是新增一個

# postman測試,地址要嚴格,斜槓有和沒有是有區別的

檢視

from rest_framework.viewsets import ModelViewSet
from .models import Book # 模組匯入使用相對匯入
# from app01.models import Book # 使用絕對匯入
from .serializer import BookSerializer
class BookView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

路由

from rest_framework.routers import SimpleRouter
from app01 import views

router = SimpleRouter()
router.register('books', views.BookView, 'books')
urlpatterns = [
    path('admin/', admin.site.urls),
]
urlpatterns += router.urls

序列化類

from .models import Book
from rest_framework import serializers

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

模型

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.DecimalField(decimal_places=2, max_digits=5)
    author = models.CharField(max_length=32)

3 cbv原始碼流程分析 (瞭解)

# cbv路由寫法:path('test/', views.TestView.as_view())---》第二個引數是函式記憶體地址---》as_view()執行完,也是一個記憶體地址---》閉包函式view的記憶體地址---》當請求來了,路由匹配成功--》執行view(request),傳入當次請求的request物件---->return self.dispatch(request, *args, **kwargs)--->View類中找dispatch---》如果是get請求就會執行檢視類中的get方法,如果是post請求,就會執行檢視類的post方法




# as_view 類的繫結方法---》View類的方法--》@classonlymethod
# dispatch核心程式碼---》getattr反射---》從當前物件(檢視類的物件)---》如果是get請求--》會拿到get方法---》handler就是get方法---》handler(request)本質就是---》get(request)
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
return handler(request, *args, **kwargs)



# 通過描述符自己寫裝飾器來裝飾類---》完成類似於property,classmethod。。

4 drf之APIView和Request物件分析(瞭解)

from django.views.generic.base import View # 最真的路徑
from django.views.generic import View  # 因為在generic包的init裡註冊了
from django.views import View       # views包的init裡註冊了
# APIView的執行流程
路由 path('order/', views.OrderView.as_view())---》第二個引數是函式記憶體地址---》APIView的as_view的執行結果---》本質還是用了View類的as_view內的view閉包函式,去掉了csrf認證----》當請求來了---》觸發view閉包函式執行,並且傳入request--->呼叫了self.dispatch-->self是檢視類的物件,從OrderView中找dispatch,但是找不到----》父類APIView中有---》本質執行的dispatch是APIView----》

# APIView的as_view方法
  view = super().as_view(**initkwargs) # 呼叫APIView的父類(View)的as_view方法
  return csrf_exempt(view) # 去掉csrf_exempt的認證,以後只要繼承了APIView後,csrf就無效了,無論中介軟體是否註釋掉

# APIView的dispatch
  def dispatch(self, request, *args, **kwargs):
    	  # request是新的drf提供的request,它是由老的django的request得到的
      	# 通過老request,生成一個新request,drf的Request的物件
        request = self.initialize_request(request, *args, **kwargs)
        # 把新的request,放到了檢視類物件中
        self.request = request
        try:
           # 執行了三大認證(認證,許可權,頻率)
            self.initial(request, *args, **kwargs)
            # self.http_method_names是個列表
            if request.method.lower() in self.http_method_names:
              	# 原來dispatch的核心程式碼
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
            # 原來dispatch寫的,但是request已經不是老request了,是新的
            response = handler(request, *args, **kwargs) # 執行檢視函式的方法
        except Exception as exc:
          	# 無論在三大認證過程中還是執行檢視函式方法過程中,只要拋了異常,都會被捕獲到
            # 處理全域性異常
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response


      
# APIView執行流程---》
  1 包裝了新的Request物件,以後檢視類中的方法中傳入的request物件都是新的
  2 在進入檢視函式之前,執行了三大認證
  3 無論三大認證還是檢視函式的方法,執行過程中出了異常,都會被處理掉
      
    
    
    
    
    
#  如何包裝的新的request
request = self.initialize_request(request, *args, **kwargs)---》APIView的initialize_request---》核心程式碼
from rest_framework.request import Request
return Request(
            request,  # 老的request
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
新的Request中:self._request = request---》新的request._request是老的request

新的:<class 'rest_framework.request.Request'>
老的:<class 'django.core.handlers.wsgi.WSGIRequest'>

# 三大認證人如何走的
self.initial(request, *args, **kwargs)---》APIView的
核心程式碼:
   self.perform_authentication(request)  # 認證
   self.check_permissions(request)   #許可權
   self.check_throttles(request) # 頻率





      
# crsf的區域性禁用--》在檢視函式上加裝飾器---》csrf_exempt裝飾器---》裝飾器本質就是一個函式
@csrf_exempt       # 裝飾器的@ 是一個語法糖(特殊語法)-->把下面的函式當引數傳入裝飾器中並且把返回結果賦值給函式名:index=csrf_exempt(index)
def index(request)
	pass
跟 csrf_exempt(index) 一毛一樣

Request物件分析

# rest_framework.request.Request ---》常用屬性和方法
request.data  # 前端post請求傳入的資料---》在老的request.POST-->老的只能處理urlencoded和formdata編碼格式,json格式不能處理---》無論前端用什麼編碼post提交的資料,都從data中獲取
request.files # 上傳的檔案物件

以後直接使用新的request.method  request.path 拿到的就是老的request.method...
物件.呼叫屬性或方法會觸發 魔法方法 __getattr__
原因在於新的request類重寫了__getattr__,以後新的request.method用的時候本質就是request._request.method
  def __getattr__(self, attr):
       try:
            return getattr(self._request, attr)  # 通過反射去老的裡面取
        except AttributeError:
            return self.__getattribute__(attr)

          
# 總結:新的request當老的用即可,只是多了個data前端post請求傳入的資料,三種編碼格式都可以
1 APIView和Request原始碼部分---》看看---》步驟寫一寫
2 原來的django的request物件中沒有data,寫個裝飾器,裝在檢視函式上(中介軟體),使得request.data-->無論什麼編碼格式,post提交資料,data都有值
def before(func):
    def inner(request,*args,**kwargs):
        request.data=request.POST
        
        res=func(request,*args,**kwargs)
        return res
    return inner

@before
def test(request):
    print(request.data) #
    return HttpResponse('ok')