1. 程式人生 > >rest_framework--序列化元件

rest_framework--序列化元件

#####序列化元件#####

一、什麼是序列化
    在python中一切皆物件,把物件從記憶體中變成可儲存或傳輸的過程稱之為序列化。
    你寫一個django專案肯定是有前後端互動的吧,雖然django也可以自己寫模板(也就是前端頁面),你要給pc端,移動端用?難道要寫兩個django專案,這樣
    是不是太浪費資源了,所以現在出了前後端分離,這樣的話,你就寫一個後端就好了,不管前端是移動端,還是pc端,我只負責傳資料過就好了。出現前後端分離
    的方案,好處還有很多,就不一一多說。
    總之,我django專案只負責返回相應的資料就好了,這就存在資料傳輸了,我後端從硬碟拿到資料,是在記憶體中的,所以我需要把記憶體中的資料,轉成一箇中間
    格式(它可以進行傳輸),前端拿到後臺傳過去的資料後,再進行操作,將這個中間格式的資料,轉成前端語言能看懂的資料型別就好了。

二、反序列化和序列化就相反了,把中間格式轉成資料型別,能夠直接使用。

三、那麼就有一個問題了,在python中哪種型別,能在前端語言中使用呢?
        有那麼一個,就是字典,它是這樣的符號 {} ,在python中就是一個數據型別
        在前端js語言中 {} 這個代表著就是一個物件
   上面這個問題解決了,那麼用哪種中間格式去進行傳輸呢?這個中間格式必須滿足python和js都可以進行序列化,反序列化
   這個中間格式就是json,可能有其他的(不太清楚)

   有了上面兩個問題的解決,那我們只需向前臺傳輸json格式的字典就好了,列表套字典也可以,這才是重點!!!!!!

四、如何在rest_framework中使用序列化呢?(Serializer的使用)
   
from rest_framework import serializers 它所在的位置 序列化元件的使用其實和forms元件的操作是差不多的,在app檔案中新建一個py檔案,拿來單獨寫序列化類。 那我寫一個圖書的序列化,目的就是為什麼要使用序列化的原因。 在新建的py檔案中: from rest_framework import serializers class BookSerializers(serializers.Serializer): name = serializers.CharField() price
= serializers.CharField() author = serializers.CharField() publish = serializers.CharField() 在檢視層(views)檔案中: class Book(APIView): def get(self,request): books = models.Book.objects.all() book_ser = BookSerializers(instance=books,many=True) book_dic
= book_ser.data return JsonResponse(book_dic) 這是很基礎的序列化使用,book_ser.data這個的返回值就是一個字典 寫一個序列化類也很簡單,寫一個普通類,然後繼承serializers.Serializer就好了 下面就寫寫上面出現過的一些方法 ----------------------------------------------------- 1、name = serializers.CharField() ----------------------------------------------------- 2、book_ser = BookSerializers(instance=books,many=True) ----------------------------------------------------- 3、book_ser.data ----------------------------------------------------- 先說name = serializers.CharField()這句,首先我們需要知道serializers是一個模組名(也就是py檔案), 上面這句程式碼,就相當於面向物件的組合,一個物件的屬性的值是另一個物件。CharField是不是很熟悉(forms那塊),用法的話,和forms元件有一些是相同 的,寫寫CharField裡的一個引數,source他可以等於表(表就是models檔案裡)的欄位名,或者方法名,但是這個名字不能跟序列化類對應的屬性名一樣。 比如:name = serializers.CharField(source='name') 這樣是不對的。 繼續還有這樣一種方法 name = serializers.SerializerMethodField(),但是要在該序列化類中寫一個方法,方法名一定叫做get_name,它的返回值, 就是name(這個name是序列化類的屬性)所對應的值,方法的名字格式就是 get_序列化類屬性的名字。 也可以更改報錯的語句 error_messages,和forms裡一樣 再說book_ser = BookSerializers(instance=books,many=True)這句,這就是生成一個序列化類的物件,肯定會執行__init__這個方法的,那就一層 一層找,這個__init__方法在哪裡,傳什麼引數進去,最終我們在BaseSerializer這個類裡找到了: BaseSerializer類 def __init__(self, instance=None, data=empty, **kwargs): self.instance = instance if data is not empty: self.initial_data = data self.partial = kwargs.pop('partial', False) self._context = kwargs.pop('context', {}) kwargs.pop('many', None) super(BaseSerializer, self).__init__(**kwargs) def __new__(cls, *args, **kwargs): # We override this method in order to automagically create # `ListSerializer` classes instead when `many=True` is set. if kwargs.pop('many', False): return cls.many_init(*args, **kwargs) return super(BaseSerializer, cls).__new__(cls, *args, **kwargs) 上面說漏了,執行init方法之前,肯定會走new這個方法,我們看這個new方法,判斷many的值是否為True or False,True的話, 執行類的many_init(*args, **kwargs),False執行其基類的new方法。 直接將many的作用吧:如果為真,那麼book_ser.data就是一個列表裡夾著字典,如果為假,那就是一個字典。它是通過判斷many的值,再進行序列化的, 假如你instance=books,這個books是一本書的物件,那麼many就應該為false(不用傳,預設為false),books是多個物件,那麼就必須many為真了。 如果你是序列化的話,那麼instance就應該為你想序列化的物件,data必須為空,也就是不傳。 如果你想反序列化的話,也就是前臺傳送的資料是一個字典,那麼data的值就是前端傳來的字典,如果該請求是新增書籍的話,那麼instance不用傳,如果是 修改書籍操作,那麼instance就是該書籍的物件了,你不傳哪本書,它怎麼知道修改哪本呢? 最後再講book_ser.data這行程式碼,它的返回值就是字典或列表裡套字典對吧,這取決於many的值 五、ModelSerializer的使用,作用和Serializer一樣。繼續拿Book為例子 class BookSerializers(serializers.ModelSerializer) class Meta: model = models.Book fields = '__all__' 寫完啦,效果和上面寫的序列化類一樣,在自定義序列化類中寫一個類,名字必須為Meta,model指定是哪個表,fields = '__all__',全部欄位, 除了上面這些,exclude=('nid',),表示出來nid,其他所有欄位,所以exclude和fields必須只能有一個。depth深度控制。 雖然'__all__'已經規定完了所有欄位的格式,你可以在下面重寫你自己哪個欄位想返回怎樣的格式,比如: nid = serializers.CharField() ---->>>意思是你可以再寫,將前面的覆蓋掉 六、HyperlinkedIdentityField的使用 作用:自動生成一個超連結(url) class BookSerializers(serializers.ModelSerializer) class Meta: model = models.Book fields = '__all__' publish = serializers.HyperlinkedIdentityField(view_name='zhu',lookup_field='publish_id',lookup_url_kwarg='pk') 檢視層: class Book(APIView): def get(self,request): books = models.Book.objects.all() book_ser = BookSerializers(instance=books,many=True,context={'request':request}) book_dic = book_ser.data return JsonResponse(book_dic) 路由層: url(r'books/',Book.as_view()), url(r'publish/(?P<pk>\d+)/$',Publish.as_view(),name='zhu'), 解釋下上面HyperlinkedIdentityField傳的引數view_name就是路由的name,通過反向解析可以拿到,lookup_field就是通過表的哪個欄位, lookup_url_kwarg就是url中的關鍵字引數。大概流程是,通過view_name拿到url,把publish_id的值賦給那個關鍵字引數。 七、校驗欄位和儲存資料功能 校驗欄位和forms元件一樣,也有區域性鉤子,全域性鉤子,也是is_valid()這個方法進行校驗,返回值為布林型別,校驗成功直接呼叫save方法, 就會儲存在資料庫中,注意呼叫save之前,你要保證欄位和你資料庫中的欄位要對得上才行。校驗失敗的話,errors這裡是錯誤資訊