Rest framework-序列化組件(Serializers)

序列化組件(Serializers)

序列化器允許將諸如查詢集和模型實例之類的復(fù)雜數(shù)據(jù)轉(zhuǎn)換為原生 Python 數(shù)據(jù)類型,然后可以將它們輕松地呈現(xiàn)為 JSON橱脸,XML 或其他內(nèi)容類型葫男。序列化器還提供反序列化抱冷,在首次驗證傳入數(shù)據(jù)之后,可以將解析的數(shù)據(jù)轉(zhuǎn)換回復(fù)雜類型梢褐。
REST framework 中的序列化類與 Django 的 Form 和 ModelForm 類非常相似旺遮。我們提供了一個 Serializer 類,它提供了一種強大的通用方法來控制響應(yīng)的輸出利职,以及一個 ModelSerializer 類趣效,它為創(chuàng)建處理模型實例和查詢集的序列化提供了有效的快捷方式。

Django的serialize序列化

class PublishView(APIView):

    def get(self,request):
        publish_list=Publish.objects.all()
        ret=serialize("json",publish_list)

        return HttpResponse(ret)

    def post(self,request):
        pass

REST framework的Serializers序列化

序列化普通字段

Publish為例
urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views


urlpatterns = [
    url(r'^admin/', admin.site.urls),

    url(r'^login/', views.LoginView.as_view()),
    url(r'^courses/', views.CourseView.as_view()),
    url(r'^publishes/', views.PublishView.as_view()),
]

models.py

class Publish(models.Model):
    nid = models.AutoField(primary_key=True)
    name=models.CharField( max_length=32)
    city=models.CharField( max_length=32)
    email=models.EmailField()

    def __str__(self):
        return self.name

class Book(models.Model):

    nid = models.AutoField(primary_key=True)
    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)

    # 與Publish建立一對多的關(guān)系,外鍵字段建立在多的一方
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
    # 與Author表建立多對多的關(guān)系,ManyToManyField可以建在兩個模型中的任意一個猪贪,自動創(chuàng)建第三張表
    authors=models.ManyToManyField(to='Author',)

    def __str__(self):
        return self.title

views.py

from app01.models import Publish
from django.core.serializers import serialize
from rest_framework.views import  APIView

from rest_framework import serializers

class PublishSerializers(serializers.Serializer):
    '''
    PublishSerializers 組件是一個集成功能組件
    到底用什么功能跷敬,取決于調(diào)用什么借口
    這是為PublishView做的組件,我們可以看出name热押,city西傀,email都是Publish具有的
    '''
    name=serializers.CharField()
    city=serializers.CharField()
    email=serializers.CharField()


class PublishView(APIView):

    def get(self,request):

        publish_list=Publish.objects.all()

        # 方式一:Django序列化組件
        # ret=serialize("json",publish_list)

        # 方式二:REST序列化組件
        # 調(diào)用PublishSerializers組件把publish_list序列化
        # 這個組件不僅可以序列化QuerySet,也可以序列化一個model對象
        # 默認many=Flase 序列化model對象桶癣,many=True序列化QuerySet
        ps=PublishSerializers(publish_list,many=True )
        # 序列化完成的數(shù)據(jù)
        ps.data
        return HttpResponse(ps.data)

    def post(self,request):
        pass

這個時候我們訪問http://127.0.0.1:8000/publishes/

OrderedDict([('name', '人民出版社'), ('city', '北京'), ('email', '123@qq.com')])OrderedDict([('name', '蘋果出版社'), ('city', '南京'), ('email', '1211@qq.com')])

OrderedDict類(有序字典)類似于定義字典的第二種方式

# 定義字典的第一種方式
d={1:2}         # {1: 2} 
# 定義字典的第二種方式
d2=dict([('a',1),(2,3)])    # {'a': 1, 2: 3}

Response響應(yīng)器

# rest_framework封裝的一個響應(yīng)器Response就不用HttpResponse拥褂,Response最后還是繼承HttpResponse,但是加了一些自己的東西
from rest_framework.response import Response
class PublishView(APIView):

    def get(self,request):

        publish_list=Publish.objects.all()

        # 方式一:Django序列化組件
        # ret=serialize("json",publish_list)

        # 方式二:REST序列化組件
        # 調(diào)用PublishSerializers組件把publish_list序列化
        # 這個組件不僅可以序列化QuerySet牙寞,也可以序列化一個model對象
        # 默認many=Flase 序列化model對象饺鹃,many=True序列化QuerySet
        ps=PublishSerializers(publish_list,many=True )
        # 序列化完成的數(shù)據(jù)
        # ps.data
        return Response(ps.data)

    def post(self,request):
        pass

現(xiàn)在再去訪問 http://127.0.0.1:8000/publishes/ 我們會發(fā)現(xiàn)是一個頁面,但是這并不是我們想要的JSON數(shù)據(jù)
其實這是REST做了一個判斷當(dāng)訪問者只有是瀏覽器來訪問我的時候,我就返回一個頁面,其他來訪問的時候返回數(shù)據(jù)
這個頁面可以直接發(fā)送POST請求,用來快速開發(fā),但是我們有更好用的工具Postman,用來模擬發(fā)送各種類型數(shù)據(jù)請求

image.png

http://127.0.0.1:8000/publishes/?format=json 加上 ?format=json就可以了!
這才是我們真正要給前端服務(wù)器的JSON數(shù)據(jù),而不是一個頁面

[{"name":"人民出版社","city":"北京","email":"123@qq.com"},{"name":"蘋果出版社","city":"南京","email":"1211@qq.com"}]

自己理解的序列化簡易偽代碼

# 自己理解的偽代碼 這兩步內(nèi)部做了什么莫秆?
ps=PublishSerializers(publish_list,many=True )
# 序列化完成的數(shù)據(jù)
# ps.data
return Response(ps.data)

# 解析
data=[]
for obj in publish_list
    # 每次循環(huán)又一個對象就生成一個字典
    # 有幾個鍵值取決于當(dāng)前序列化組件有幾個鍵,拿PublishSerializers為例
    data.append({
        "name":obj.name,
        "city":obj.city,
        "email":obj.email,
    })
    # 以后再拿PublishSerializers這個實例化對象data方法的時候悔详,就是上面序列化的結(jié)果了
    self.data=data

這個時候我們可以得出一個結(jié)論PublishSerializers寫什么字段序列化什么字段

序列化一對多,多對多字段

針對一對多

Book為例
urls.py

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^login/$', views.LoginView.as_view()),
    url(r'^courses/$', views.CourseView.as_view()),
    url(r'^publishes/$', views.PublishView.as_view()),
    url(r'^books/$',views.BookView.as_view()),
]

models.py數(shù)據(jù)庫數(shù)據(jù)自己填寫

class Book(models.Model):

    nid = models.AutoField(primary_key=True)
    title = models.CharField( max_length=32)
    publishDate=models.DateField()
    price=models.DecimalField(max_digits=5,decimal_places=2)

    # 與Publish建立一對多的關(guān)系,外鍵字段建立在多的一方
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
    # 與Author表建立多對多的關(guān)系,ManyToManyField可以建在兩個模型中的任意一個镊屎,自動創(chuàng)建第三張表
    authors=models.ManyToManyField(to='Author',)

    def __str__(self):
        return self.title

views.py

from app01.models import Book
class BookSerializers(serializers.Serializer):
    title=serializers.CharField()
    price=serializers.CharField()
    publishDate=serializers.DateField()
    # 按照我們上邊刨析的偽代碼虎敦,這里什么都不懂按照CharField來垄惧,也就是按照普通字段來
    # 所以鍵就是publish,值就是obj.publish一本書點publish就是這本書關(guān)聯(lián)的對象
    publish=serializers.CharField()


class BookView(APIView):

    def get(self,request):
        book_list=Book.objects.all()
        ps=BookSerializers(book_list,many=True)
        # 序列化完成的數(shù)據(jù)
        return Response(ps.data)

    def post(self,request):
        pass

訪問 http://127.0.0.1:8000/books/

[
    {
        "title": "西游記",
        "price": "123.00",
        "publishDate": "2018-08-01",
        "publish": "蘋果出版社"  
        # 這里publish對應(yīng)的值是對應(yīng)出版社models.py
        # def __str__(self):
        #    return self.name
        # 所以return self.什么就顯示什么
        # 這里return返回的很多地方都會用到,不能亂改,所以不可行
    },
    {
        "title": "度假先鋒的故事",
        "price": "11.00",
        "publishDate": "2018-08-01",
        "publish": "蘋果出版社"
    }
]

source寫誰就相當(dāng)于obj.publish.email不是默認的obj.publish

class BookSerializers(serializers.Serializer):
    title=serializers.CharField()
    price=serializers.CharField()
    publishDate=serializers.DateField()
    # 按照我們上邊刨析的偽代碼旋圆,這里什么都不懂按照CharField來归苍,也就是按照普通字段來
    # 所以鍵就是publish用狱,值就是obj.publish一本書點publish就是這本書關(guān)聯(lián)的對象
    # 所以這里source寫誰就相當(dāng)于obj.publish.email不是默認的obj.publish
    publish=serializers.CharField(source='publish.email')
    # 只要source指定好去取什么字段,鍵就不用在固定寫對應(yīng)的models.py拼弃,沒有的話就實例化時變量必須對應(yīng)models.py
    xxx=serializers.CharField(source="publish.name")
[
    {
        "title": "西游記",
        "price": "123.00",
        "publishDate": "2018-08-01",
        "publish": "1211@qq.com",
        "xxx": "蘋果出版社"
    },
    {
        "title": "度假先鋒的故事",
        "price": "11.00",
        "publishDate": "2018-08-01",
        "publish": "1211@qq.com",
        "xxx": "蘋果出版社"
    }
]
針對多對多

models.py

from app01.models import Book
class BookSerializers(serializers.Serializer):
    title=serializers.CharField()
    price=serializers.CharField()
    publishDate=serializers.DateField()
    # 針對一對多
    # 按照我們上邊刨析的偽代碼夏伊,這里什么都不懂按照CharField來,也就是按照普通字段來
    # 所以鍵就是publish肴敛,值就是obj.publish一本書點publish就是這本書關(guān)聯(lián)的對象
    # 所以這里source寫誰就相當(dāng)于obj.publish.email不是默認的obj.publish
    publish=serializers.CharField(source='publish.email')
    # 只要source指定好去取什么字段署海,鍵就不用在固定寫對應(yīng)的models.py,沒有的話就實例化時變量必須對應(yīng)models.py
    xxx=serializers.CharField(source="publish.name")
    # 針對多對多
    # SerializerMethodField 聲明這是個多對多字段
    authors=serializers.SerializerMethodField()
    # 聲明好多對多字段医男,底下緊跟著定義一個方法
    # 此時的obj就是你循環(huán)book_list的obj對象
    def get_authors(self,obj):
        data=[]
        # for 循環(huán) 對象關(guān)聯(lián)Author表所有的對象
        for i in obj.authors.all():
            temp = []
            temp.append(i.pk)
            temp.append(i.name)
            data.append(temp)
        return data

 '''
# 自己理解的偽代碼 這兩步內(nèi)部做了什么?
ps=PublishSerializers(publish_list,many=True )
# 序列化完成的數(shù)據(jù)
# ps.data
return Response(ps.data)

# 解析
data=[]
for obj in publish_list
    # 每次循環(huán)又一個對象就生成一個字典
    # 有幾個鍵值取決于當(dāng)前序列化組件有幾個鍵捻勉,拿PublishSerializers為例
    data.append({
        "name":obj.name,
        "city":obj.city,
        "email":obj.email,
        # if 字段是多對多字段:
        "authors":get_authors(obj)
    })
    # 以后再拿PublishSerializers這個實例化對象data方法的時候镀梭,就是上面序列化的結(jié)果了
    self.data=data
'''

class BookView(APIView):

    def get(self,request):
        book_list=Book.objects.all()
        ps=BookSerializers(book_list,many=True)
        # 序列化完成的數(shù)據(jù)
        return Response(ps.data)

    def post(self,request):
        pass

封裝成一個模塊

像這種的我們完全可以封裝成一個模塊views.py來調(diào)用,我這里就新建一個serializer.py來封裝
class PublishSerializers(serializers.Serializer):
class BookSerializers(serializers.Serializer):
然后views.py
from app01.serializer import PublishSerializers,BookSerializers導(dǎo)入一下

序列化之(ModelSerializer)

serializer.py
Publish

from app01.models import Publish
# 自定義不強的話用ModelSerializer就非常簡單了
class PublishSerializers(serializers.ModelSerializer):
    class Meta:
        # 指定序列化的表
        model=Publish
        # 排除不序列化的字段,這是一個元祖逗號結(jié)尾
        exclude=("nid",)
        # 序列化所有數(shù)據(jù),與exclude不能并存
        # fields="__all__"
[
    {
        "name": "人民出版社",
        "city": "北京",
        "email": "123@qq.com"
    },
    {
        "name": "蘋果出版社",
        "city": "南京",
        "email": "1211@qq.com"
    }
]

Book

from app01.models import Book
class BookSerializers(serializers.ModelSerializer):
   class Meta:
       model=Book
       # 序列化所有數(shù)據(jù)踱启,與exclude不能并存
       fields="__all__"
[
    {
        "nid": 2,
        "title": "西游記",
        "publishDate": "2018-08-01",
        "price": "123.00",
        "publish": 2,   # 不是我們想要的數(shù)據(jù)
        "authors": [    # 我們會發(fā)現(xiàn)這authors并不是我們想要的數(shù)據(jù)
            2,
            1,
            3
        ]
    },
    {
        "nid": 3,
        "title": "度假先鋒的故事",
        "publishDate": "2018-08-01",
        "price": "11.00",
        "publish": 2,
        "authors": [
            2,
            1
        ]
    }
]

更改代碼獲取我們想要的字段數(shù)據(jù)

from app01.models import Book
class BookSerializers(serializers.ModelSerializer):
   class Meta:
       model=Book
       # 序列化所有數(shù)據(jù)报账,與exclude不能并存
       fields="__all__"

   # 這樣加上去之后,就是不要他創(chuàng)建的字段了埠偿,用我自己寫的自定義字段,有的話覆蓋透罢,沒有的話添加

   publish=serializers.CharField(source='publish.email')
   xxx=serializers.CharField(source="publish.name")

   # SerializerMethodField 聲明這是個多對多字段
   authors=serializers.SerializerMethodField()
   # 聲明好多對多字段,底下緊跟著定義一個方法
   # 此時的obj就是你循環(huán)book_list的obj對象
   def get_authors(self,obj):
       data=[]
       # for 循環(huán) 對象關(guān)聯(lián)Author表所有的對象
       for i in obj.authors.all():
           temp = []
           temp.append(i.pk)
           temp.append(i.name)
           data.append(temp)
       return data
[
    {
        "nid": 2,
        "publish": "1211@qq.com",
        "xxx": "蘋果出版社",
        "authors": [
            [
                2,
                "moyan"
            ],
            [
                1,
                "allen"
            ],
            [
                3,
                "fuming"
            ]
        ],
        "title": "西游記",
        "publishDate": "2018-08-01",
        "price": "123.00"
    },
    {
        "nid": 3,
        "publish": "1211@qq.com",
        "xxx": "蘋果出版社",
        "authors": [
            [
                2,
                "moyan"
            ],
            [
                1,
                "allen"
            ]
        ],
        "title": "度假先鋒的故事",
        "publishDate": "2018-08-01",
        "price": "11.00"
    }
]
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冠蒋,一起剝皮案震驚了整個濱河市羽圃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抖剿,老刑警劉巖朽寞,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異斩郎,居然都是意外死亡脑融,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門缩宜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來肘迎,“玉大人,你說我怎么就攤上這事〖瞬迹” “怎么了窿侈?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秋茫。 經(jīng)常有香客問我史简,道長,這世上最難降的妖魔是什么肛著? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任圆兵,我火速辦了婚禮,結(jié)果婚禮上枢贿,老公的妹妹穿的比我還像新娘殉农。我一直安慰自己,他們只是感情好局荚,可當(dāng)我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布超凳。 她就那樣靜靜地躺著,像睡著了一般耀态。 火紅的嫁衣襯著肌膚如雪轮傍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天首装,我揣著相機與錄音创夜,去河邊找鬼。 笑死仙逻,一個胖子當(dāng)著我的面吹牛驰吓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播系奉,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼檬贰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了缺亮?” 一聲冷哼從身側(cè)響起翁涤,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瞬内,沒想到半個月后迷雪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡虫蝶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年章咧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片能真。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡赁严,死狀恐怖扰柠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疼约,我是刑警寧澤卤档,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站程剥,受9級特大地震影響劝枣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜织鲸,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一舔腾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧搂擦,春花似錦稳诚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至橱夭,卻和暖如春氨距,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背徘钥。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工衔蹲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人呈础。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像橱健,于是被迫代替她去往敵國和親而钞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容