序列化組件(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ù)請求
在 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"
}
]