序列化與反序列化、def的介紹與快速使用、cbv源碼分析、APIView與request對象分析

  • 2022 年 3 月 29 日
  • 筆記

今日內容概要

  • 序列化與反序列化
  • def介紹和快速使用
  • 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)  # django 2.x
	視圖函數中:通過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項目可能有問題,運行不了
  
	django2.2以下--->drf降版本
	django3.x---->drf使用最新
# 官方說明版本問題:
	Python (3.6, 3.7, 3.8, 3.9, 3.10)
	Django (2.2, 3.0, 3.1, 3.2, 4.0)

# 此後演示 以django 2.2 djangorestframework 最新版為例

image

2.1、快速使用

# 針對於一個表,需要寫那些介面---》5個
	以後看到的所有介面都是這5個的變形:
	使用postman測試:
		-查詢所有---》get 請求->//127.0.0.1:8000/books/
		-查詢一個---》get 請求->//127.0.0.1:8000/books/2/
		-新增一個---》post 請求->//127.0.0.1:8000/books/ body中帶數據
                
		-修改-----》put 請求:修改單個欄位或者多個欄位,patch 請求:只修改某個欄位--->實際編碼中,基本都用put
			//127.0.0.1:8000/books/1/ body體中傳入修改的數據
		-刪除一個---》delete-->//127.0.0.1:8000/books/1/
                
                
# 登陸介面---》本質其實是查詢一個

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

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

image

image

視圖 views.py

# 寫5個介面---》配5個視圖函數
# 使用drf來寫-->使用視圖類
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

路由 urls.py

from django.contrib import admin
from django.urls import path

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

序列化類 在app01下創建serializer.py文件

from .models import Book
from rest_framework import serializers


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

模型 models.py

from django.db import models


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())
"""
第二個參數是函數記憶體地址 views.TestView.as_view()

as_view()執行完,也是一個記憶體地址>>>閉包函數view的記憶體地址
	當請求來了,路由匹配成功
	執行view(request) 傳入當次請求的request對象

執行view(request) 本質上就是:
	return self.dispatch(request, *args, **kwargs)
	去View類中找 dispatch
		如果是get請求就會執行視圖類中的get方法
		如果是post請求,就會執行視圖類的post方法
"""
	

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

# 可以通過描述符自己寫裝飾器來裝飾類(了解)
	完成類似於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里註冊了 generic.base


# 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)  # 頻率
    
    
# APIView的as_view方法
	view = super().as_view(**initkwargs)  # 調用APIView的父類(View)的as_view方法
	return csrf_exempt(view)  # 去掉csrf_exempt的認證,以後只要繼承了APIView後,csrf就無效了,無論中間件是否注釋掉

# 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請求傳入的數據,三種編碼格式都可以

image