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"
    }
]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,183评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,850评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,766评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,854评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,871评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,457评论 1 311
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,999评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,914评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,465评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,543评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,675评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,354评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,029评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,514评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,616评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,091评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,685评论 2 360

推荐阅读更多精彩内容