美文网首页程序员程序园
Rest framework-序列化组件(Serializers

Rest framework-序列化组件(Serializers

作者: 墨颜丶 | 来源:发表于2018-08-02 01:54 被阅读245次

    序列化组件(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"
        }
    ]
    

    相关文章

      网友评论

        本文标题:Rest framework-序列化组件(Serializers

        本文链接:https://www.haomeiwen.com/subject/sqgdvftx.html