序列化组件(Serializers)
序列化器允许将诸如查询集和模型实例之类的复杂数据转换为原生 Python
数据类型,然后可以将它们轻松地呈现为 JSON
,XML
或其他内容类型。序列化器还提供反序列化,在首次验证传入数据之后,可以将解析的数据转换回复杂类型。
REST framework
中的序列化类与 Django 的 Form 和 ModelForm
类非常相似。我们提供了一个 Serializer
类,它提供了一种强大的通用方法来控制响应的输出,以及一个 ModelSerializer
类,它为创建处理模型实例和查询集的序列化提供了有效的快捷方式。
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建立一对多的关系,外键字段建立在多的一方
publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
# 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
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 组件是一个集成功能组件
到底用什么功能,取决于调用什么借口
这是为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序列化组件
# 调用PublishSerializers组件把publish_list序列化
# 这个组件不仅可以序列化QuerySet,也可以序列化一个model对象
# 默认many=Flase 序列化model对象,many=True序列化QuerySet
ps=PublishSerializers(publish_list,many=True )
# 序列化完成的数据
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响应器
# rest_framework封装的一个响应器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序列化组件
# 调用PublishSerializers组件把publish_list序列化
# 这个组件不仅可以序列化QuerySet,也可以序列化一个model对象
# 默认many=Flase 序列化model对象,many=True序列化QuerySet
ps=PublishSerializers(publish_list,many=True )
# 序列化完成的数据
# ps.data
return Response(ps.data)
def post(self,request):
pass
现在再去访问 http://127.0.0.1:8000/publishes/ 我们会发现是一个页面,但是这并不是我们想要的JSON数据
其实这是REST做了一个判断当访问者只有是浏览器来访问我的时候,我就返回一个页面,其他来访问的时候返回数据
这个页面可以直接发送POST请求,用来快速开发,但是我们有更好用的工具Postman,用来模拟发送各种类型数据请求
在 http://127.0.0.1:8000/publishes/?format=json 加上 ?format=json
就可以了!
这才是我们真正要给前端服务器的JSON数据,而不是一个页面
[{"name":"人民出版社","city":"北京","email":"123@qq.com"},{"name":"苹果出版社","city":"南京","email":"1211@qq.com"}]
自己理解的序列化简易伪代码
# 自己理解的伪代码 这两步内部做了什么?
ps=PublishSerializers(publish_list,many=True )
# 序列化完成的数据
# ps.data
return Response(ps.data)
# 解析
data=[]
for obj in publish_list
# 每次循环又一个对象就生成一个字典
# 有几个键值取决于当前序列化组件有几个键,拿PublishSerializers为例
data.append({
"name":obj.name,
"city":obj.city,
"email":obj.email,
})
# 以后再拿PublishSerializers这个实例化对象data方法的时候,就是上面序列化的结果了
self.data=data
这个时候我们可以得出一个结论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
数据库数据自己填写
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建立一对多的关系,外键字段建立在多的一方
publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
# 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表
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就是这本书关联的对象
publish=serializers.CharField()
class BookView(APIView):
def get(self,request):
book_list=Book.objects.all()
ps=BookSerializers(book_list,many=True)
# 序列化完成的数据
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对应的值是对应出版社models.py
# def __str__(self):
# return self.name
# 所以return self.什么就显示什么
# 这里return返回的很多地方都会用到,不能乱改,所以不可行
},
{
"title": "度假先锋的故事",
"price": "11.00",
"publishDate": "2018-08-01",
"publish": "苹果出版社"
}
]
source
写谁就相当于obj.publish.email不是默认的obj.publish
class BookSerializers(serializers.Serializer):
title=serializers.CharField()
price=serializers.CharField()
publishDate=serializers.DateField()
# 按照我们上边刨析的伪代码,这里什么都不懂按照CharField来,也就是按照普通字段来
# 所以键就是publish,值就是obj.publish一本书点publish就是这本书关联的对象
# 所以这里source写谁就相当于obj.publish.email不是默认的obj.publish
publish=serializers.CharField(source='publish.email')
# 只要source指定好去取什么字段,键就不用在固定写对应的models.py,没有的话就实例化时变量必须对应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就是这本书关联的对象
# 所以这里source写谁就相当于obj.publish.email不是默认的obj.publish
publish=serializers.CharField(source='publish.email')
# 只要source指定好去取什么字段,键就不用在固定写对应的models.py,没有的话就实例化时变量必须对应models.py
xxx=serializers.CharField(source="publish.name")
# 针对多对多
# SerializerMethodField 声明这是个多对多字段
authors=serializers.SerializerMethodField()
# 声明好多对多字段,底下紧跟着定义一个方法
# 此时的obj就是你循环book_list的obj对象
def get_authors(self,obj):
data=[]
# for 循环 对象关联Author表所有的对象
for i in obj.authors.all():
temp = []
temp.append(i.pk)
temp.append(i.name)
data.append(temp)
return data
'''
# 自己理解的伪代码 这两步内部做了什么?
ps=PublishSerializers(publish_list,many=True )
# 序列化完成的数据
# ps.data
return Response(ps.data)
# 解析
data=[]
for obj in publish_list
# 每次循环又一个对象就生成一个字典
# 有几个键值取决于当前序列化组件有几个键,拿PublishSerializers为例
data.append({
"name":obj.name,
"city":obj.city,
"email":obj.email,
# if 字段是多对多字段:
"authors":get_authors(obj)
})
# 以后再拿PublishSerializers这个实例化对象data方法的时候,就是上面序列化的结果了
self.data=data
'''
class BookView(APIView):
def get(self,request):
book_list=Book.objects.all()
ps=BookSerializers(book_list,many=True)
# 序列化完成的数据
return Response(ps.data)
def post(self,request):
pass
封装成一个模块
像这种的我们完全可以封装成一个模块views.py来调用,我这里就新建一个serializer.py来封装
class PublishSerializers(serializers.Serializer):
class BookSerializers(serializers.Serializer):
然后views.py
from app01.serializer import PublishSerializers,BookSerializers
导入一下
序列化之(ModelSerializer)
serializer.py
Publish
from app01.models import Publish
# 自定义不强的话用ModelSerializer就非常简单了
class PublishSerializers(serializers.ModelSerializer):
class Meta:
# 指定序列化的表
model=Publish
# 排除不序列化的字段,这是一个元祖逗号结尾
exclude=("nid",)
# 序列化所有数据,与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
# 序列化所有数据,与exclude不能并存
fields="__all__"
[
{
"nid": 2,
"title": "西游记",
"publishDate": "2018-08-01",
"price": "123.00",
"publish": 2, # 不是我们想要的数据
"authors": [ # 我们会发现这authors并不是我们想要的数据
2,
1,
3
]
},
{
"nid": 3,
"title": "度假先锋的故事",
"publishDate": "2018-08-01",
"price": "11.00",
"publish": 2,
"authors": [
2,
1
]
}
]
更改代码获取我们想要的字段数据
from app01.models import Book
class BookSerializers(serializers.ModelSerializer):
class Meta:
model=Book
# 序列化所有数据,与exclude不能并存
fields="__all__"
# 这样加上去之后,就是不要他创建的字段了,用我自己写的自定义字段,有的话覆盖,没有的话添加
publish=serializers.CharField(source='publish.email')
xxx=serializers.CharField(source="publish.name")
# SerializerMethodField 声明这是个多对多字段
authors=serializers.SerializerMethodField()
# 声明好多对多字段,底下紧跟着定义一个方法
# 此时的obj就是你循环book_list的obj对象
def get_authors(self,obj):
data=[]
# for 循环 对象关联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"
}
]
网友评论