Rest framework-序列化组件(Serializers)

序列化组件(Serializers)

序列化器允许将诸如查询集和模型实例之类的复杂数据转换为原生 Python 数据类型,然后可以将它们轻松地呈现为 JSONXML 或其他内容类型。序列化器还提供反序列化,在首次验证传入数据之后,可以将解析的数据转换回复杂类型。
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,用来模拟发送各种类型数据请求

image.png

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"
    }
]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容