• 第三章 restframework——序列化组件


    第三章 restframework——序列化组件

    一、django自带的序列化组件serializers

    二、restframework的序列化组件Serializer

    三、restframework的序列化组件ModelSerializer

    四、restframework的序列化组件超链接字段hypermedialink

    五、restframework的序列化组件之请求数据校验和保存功能

    六、补充内容

    一、django自带的序列化组件serializers

    先来看看django自带的cbv的json写法,然后我们再来看下restframework的写法

    【django】序列化

    class PublishView(View):
        def get(self,request):
            # 方式一
            publish_list = list(Publish.objects.all().values('name','email'))
            return HttpResponse(json.dumps(publish_list))
            # 方式二
            from django.forms.models import model_to_dict
            publish_list = Publish.objects.all()
            temp = []
            for obj in publish_list:
                temp.append(model_to_dict(obj))
            return HttpResponse(json.dumps(temp))
            # 方式三
            from django.core import serializers
            publish_list = Publish.objects.all()
            temp = serializers.serialize("json",publish_list)
            return HttpResponse(temp)

    使用步骤:

    导入模块

    from django.core import serializers
    def persons(request):
        ret = models.Person.objects.all()
        # person_list = []
        # for i in ret:
        #     person_list.append({"name":i.name,"age":i.age})
        # print(person_list)
        # import json
        # s = json.dumps(person_list)
        # print(s)
        from django.core import serializers
        s = serializers.serialize("json",ret)
        print(s)
        return HttpResponse(s)

    二、restframework的序列化组件Serializer

    准备工作

    models.py

    from django.db import models
    
    # Create your models here.
    
    
    class Book(models.Model):
        title=models.CharField(max_length=32)
        price=models.IntegerField()
        pub_date=models.DateField()
        publish=models.ForeignKey("Publish")
        authors=models.ManyToManyField("Author")
        def __str__(self):
            return self.title
    
    class Publish(models.Model):
        name=models.CharField(max_length=32)
        email=models.EmailField()
        def __str__(self):
            return self.name
    
    class Author(models.Model):
        name=models.CharField(max_length=32)
        age=models.IntegerField()
        def __str__(self):
            return self.name
    View Code

    【restframework】序列化

    from django.shortcuts import *
    from django.views import View
    from .models import Publish
    from rest_framework.views import APIView
    import json
    # Create your views here.
    
    
    from rest_framework import serializers
    from rest_framework.response import Response
    
    
    # 为queryset,model对象做序列化
    class PublishSerializers(serializers.Serializer):
        # 下面写的字段取决于你需要哪些字段做序列化
        name = serializers.CharField()
        email = serializers.CharField()
    
    
    class PublishView(View):
        def get(self, request):
            publish_list = Publish.objects.all()    #queryset对象
            pb = PublishSerializers(publish_list, many=True)
            # many = true 代表前面传入的参数是queryset对象
            print(pb.data)
    
            publish1 = Publish.objects.filter(pk=1).first()
            print(publish1)        # publish对象
            pb = PublishSerializers(publish1,many=False)
            # PublishSerializers(model_obj,many = false)
            # many = false 代表前面传入的参数是model对象
            # 默认many = false,所以如果是model对象可以不用写many
            print(pb.data)
            return HttpResponse(pb.data)

    使用步骤:

    1.导入模块

    from rest_framework import serializers

    2.写需要序列化的类(一般以类名+Serializers命名)

    # 为queryset,model对象做序列化
    class PublishSerializers(serializers.Serializer):
        # 下面写的字段取决于你需要哪些字段做序列化
        name = serializers.CharField()
        email = serializers.CharField()
        # publish=serializers.CharField(source="publish.name")
        # authors=serializers.CharField(source="authors.all")

    注意:

    source 如果是字段,会显示字段,如果是方法,会执行方法,不用加括号(authors=serializers.CharField(source='authors.all'))

    如在模型中定义一个方法,直接可以在在source指定执行

    3.在视图函数内调用序列化的类,使用restframework封装的Response类返回Response实例化对象

    class PublishView(View):
        def get(self, request):
            publish_list = Publish.objects.all()    #queryset对象
            pb = PublishSerializers(publish_list, many=True)
            # many = true 代表前面传入的参数是queryset对象
            print(pb.data)
    
            publish1 = Publish.objects.filter(pk=1).first()
            print(publish1)        # publish对象
            pb = PublishSerializers(publish1,many=False)
            # PublishSerializers(model_obj,many = false)
            # many = false 代表前面传入的参数是model对象
            # 默认many = false,所以如果是model对象可以不用写many
            print(pb.data)
            return HttpResponse(pb.data)

    注意:

    many=true,代表前面传入的参数需是queryset对象,而many=false,代表前面传入的是publish对象,并非指的是1个queryset对象。

    上面的演示是基于单表的简单操作,下面对Book表(存在多对多关系)进行演示

    class BookSerializers(serializers.Serializer):
        title = serializers.CharField(max_length=32)
        price = serializers.IntegerField()
        pub_date = serializers.DateField()
        publish = serializers.CharField(source="publish.name")
        # authors=serializers.CharField(source="authors.all") #这样会返回queryset对象,看起来还不是特别舒服
        authors = serializers.SerializerMethodField() # 这个方法只是为多对多服务的,下面要写类似钩子的方法
        def get_authors(self,obj):
            temp = []
            for obj in obj.authors.all():
                temp.append(obj.name)
            return temp
    class BookView(APIView):
        def get(self,request):
            book_list = Book.objects.all()
            bs = BookSerializers(book_list,many=True)
            '''
            序列化BookSerializers(book_list,many=True)做了如下操作:
            temp = []
            for obj in book_list:
                temp.append({
                    "title":obj.title,
                    "price":obj.price,
                    "pub_date":obj.pub_date,
                    "publish":obj.publish,   # 这里的返回值就是上面get_authors的返回值
                })                  
            '''
            return Response(bs.data)
    
        def post(self,request):
            pass

    三、restframework的序列化组件ModelSerializer

    大幅度简化Serializer操作

     

     如果要指定一对多或多对多显示的传输字段可以参照上面重写get_方法名方法

    class BookSerializers(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            # fields = "__all__"
            fields=['nid','title','authors','publish']
            # exclude=('nid',)   #不能跟fields同时用
            # depth = 1    #深度控制,写 几 往里拿几层,层数越多,响应越慢,官方建议0--10之间,个人建议最多3层
        publish=serializers.SerializerMethodField()
        def get_publish(self,obj):
            return obj.publish.name
        authors=serializers.SerializerMethodField()
        def get_authors(self,obj):
            ret=obj.authors.all()
            ss=AuthorSerializer(ret,many=True)
            return ss.data

     如果要指定一对多或多对对显示的传输字段需要重写create方法

    多本书的相关操作涉及get和post,那么单本书的操作则涉及get,put,delete

    让我们用ModelSerializer尝试做更多操作

    【books】BookModelSerializer准备

    class BookModelSerializers(serializers.ModelSerializer):
        class Meta:
            model = Book # 表名
            fields = "__all__" # 默认把所有字段写入,不包括自己写的get_authors方法
            # field = ['nid','title','authors','publish'] # 指定字段
            # exclude = ('nid')  # 除了...字段,不能跟fields同时用
            # depth = 1 #深度控制,写 几 往里拿几层,层数越多,响应越慢,官方建议0--10之间,个人建议最多3层
        # 如果要指定一对多,或多对多显示的字段需要重写create方法
        publish = serializers.CharField(source='publish.pk')
        def create(self, validated_data):
            # print('validated_data',validated_data)
            book = Book.objects.create(
                title=validated_data['title'],
                price=validated_data['price'],
                pub_date=validated_data['pub_date'],
                publish_id=validated_data['publish']['pk']
            )
            book.authors.add(*validated_data['authors'])
            return book

    books的【get】查看书籍

    class BookView(APIView):
        def get(self,request):
            # get请求数据
            book_list = Book.objects.all()
            bs = BookModelSerializers(book_list,many=True)
            '''
            序列化BookSerializers(book_list,many=True)做了如下操作:
            temp = []
            for obj in book_list:
                temp.append({
                    "title":obj.title,
                    "price":obj.price,
                    "pub_date":obj.pub_date,
                    "publish":obj.publish,   # 这里的返回值就是上面get_authors的返回值
                })                  
            '''
            return Response(bs.data)

    books的【post】添加一本书籍(添加完之后可以再尝试用Postman发送get请求查看所有书籍信息)

    class BookView(APIView):
        def get(self,request):
            ...
        def post(self,request):
            # post请求数据
            bs = BookModelSerializers(data=request.data)
            if bs.is_valid():
                print(bs.validated_data)
                bs.save()  # create方法
                return Response(bs.data)
            else:
                return HttpResponse(bs.errors)

     

    【bookdetail】BookDetailModelSerializer准备

    先处理url 

     

    bookdetail的【get】获取一本书

    bookdetail的【put】修改一本书

    bookdetail的【delete】获取一本书

     

    四、restframework的序列化组件超链接字段hypermedialink

    让我们再来写个publishdetail,你会发现里面的逻辑竟然和bookdetail一样,那restframework也有对应的方法可以简化

    class BookSerializers(serializers.ModelSerializer):
          publish= serializers.HyperlinkedIdentityField(
                         view_name='publish_detail',
                         lookup_field="publish_id",
                         lookup_url_kwarg="pk")
          class Meta:
              model=Book
              fields="__all__"
              #depth=1


    res=BookSerializers(ret,many=True,context={'request': request})

    五、restframework的序列化组件之请求数据校验和保存功能

    class BookSerializers(serializers.ModelSerializer):
        class Meta:
            model=Book
            fields="__all__"
    
    #————————
    class BookView(APIView):
    
        def post(self, request):
    
            # 添加一条数据
            print(request.data)
    
            bs=BookSerializers(data=request.data)
            if bs.is_valid():
                bs.save()  # 生成记录
                return Response(bs.data)
            else:
    
                return Response(bs.errors)
    class BookSerializer1(serializers.Serializer):
        title=serializers.CharField(error_messages={'required': '标题不能为空'})
    
    #这种方式要保存,必须重写create方法

    通过源码查看留的校验字段的钩子函数:

    #is_valid---->self.run_validation-(执行Serializer的run_validation)-->self.to_internal_value(data)---(执行Serializer的run_validation:485行)
    def validate_title(self, value):
            from rest_framework import exceptions
            raise exceptions.ValidationError('看你不顺眼')
            return value
    
    #全局
    def validate(self, attrs):
        from rest_framework import exceptions
        if attrs.get('title')== attrs.get('title2'):
            return attrs
        else:
            raise exceptions.ValidationError('不想等啊')

    附上代码调试用:

    """restdemo URL Configuration
    
    The `urlpatterns` list routes URLs to views. For more information please see:
        https://docs.djangoproject.com/en/1.11/topics/http/urls/
    Examples:
    Function views
        1. Add an import:  from my_app import views
        2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
    Class-based views
        1. Add an import:  from other_app.views import Home
        2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
    Including another URLconf
        1. Import the include() function: from django.conf.urls import url, include
        2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
    """
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^publishes/$',views.PublishView.as_view()),
        url(r'^publishes/(?P<pk>d+)/$',views.PublishDetailView.as_view(),name='publish_detail'),
        url(r'^books/$',views.BookView.as_view()),
        url(r'^books/(d+)/$',views.BookDetailView.as_view())
    ]
    urls.py
    from django.db import models
    
    # Create your models here.
    from django.db import models
    
    # Create your models here.
    
    
    class Book(models.Model):
        title=models.CharField(max_length=32)
        price=models.IntegerField()
        pub_date=models.DateField()
        publish=models.ForeignKey("Publish")
        authors=models.ManyToManyField("Author")
        def __str__(self):
            return self.title
    
    class Publish(models.Model):
        name=models.CharField(max_length=32)
        email=models.EmailField()
        # def __str__(self):
        #     return self.name
    
    class Author(models.Model):
        name=models.CharField(max_length=32)
        age=models.IntegerField()
        def __str__(self):
            return self.name
    models.py
    from django.shortcuts import *
    from django.views import View
    from .models import *
    import json
    # Create your views here.
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from .all_serializers import *
    
    
    
    # class BookSerializers(serializers.Serializer):
    #     title = serializers.CharField(max_length=32)
    #     price = serializers.IntegerField()
    #     pub_date = serializers.DateField()
    #     publish = serializers.CharField(source="publish.name")
    #     # authors=serializers.CharField(source="authors.all") #这样会返回queryset对象,看起来还不是特别舒服
    #     authors = serializers.SerializerMethodField() # 这个方法只是为多对多服务的,下面要写类似钩子的方法
    #     def get_authors(self,obj):
    #         temp = []
    #         for obj in obj.authors.all():
    #             temp.append(obj.name)
    #         return temp
    
    class BookView(APIView):
        def get(self,request):
            # get请求数据
            book_list = Book.objects.all()
            bs = BookModelSerializers(book_list,many=True)
            '''
            序列化BookSerializers(book_list,many=True)做了如下操作:
            temp = []
            for obj in book_list:
                temp.append({
                    "title":obj.title,
                    "price":obj.price,
                    "pub_date":obj.pub_date,
                    "publish":obj.publish,   # 这里的返回值就是上面get_authors的返回值
                })                  
            '''
            return Response(bs.data)
    
        def post(self,request):
            # post请求数据
            bs = BookModelSerializers(data=request.data)
            if bs.is_valid():
                print(bs.validated_data)
                bs.save()  # create方法
                return Response(bs.data)
            else:
                return HttpResponse(bs.errors)
    
    
    class BookDetailView(APIView):
        def get(self,request,id):
            book = Book.objects.filter(pk=id).first()
            bs = BookModelSerializers(book)
            return Response(bs.data)
        def put(self,request,id):
            book = Book.objects.filter(pk=id).first()
            # 因为是做更新操作,所以要写data=request.data,把新数据放进去
            bs = BookModelSerializers(book,data=request.data)
            if bs.is_valid():
                bs.save()
                return Response(bs.data)
            else:
                return Response(bs.errors)
        def delete(self,request,id):
            Book.objects.filter(pk=id).delete()
            # 删除操作返回空即可
            return Response()
    
    
    class PublishView(APIView):
        def get(self, request):
            publish_list = Publish.objects.all()
            ps = PublishModelSerializers(publish_list, many=True)
            return Response(ps.data)
            # 取数据
            # print('restframework', request.data)
            # print('restframework type', type(request.data))
            # print('restframework', request._request.GET)
            # print('restframework type', type(request._request.GET))
            # print('restframework', request.GET)
            # print('restframework type', type(request.GET))
            # return HttpResponse('ok')
            # 序列化
            # publish_list = Publish.objects.all()    #queryset对象
            # pb = PublishSerializers(publish_list, many=True)
            # many = true 代表前面传入的参数是queryset对象
            # print(pb.data)
    
            # publish1 = Publish.objects.filter(pk=1).first()
            # print(publish1)        # publish对象
            # pb = PublishSerializers(publish1,many=False)
            # PublishSerializers(model_obj,many = false)
            # many = false 代表前面传入的参数是model对象
            # 默认many = false,所以如果是model对象可以不用写many
            # print(pb.data)
            # return HttpResponse(pb.data)
    
            # 方式一
            # publish_list = list(Publish.objects.all().values('name','email'))
            # return HttpResponse(json.dumps(publish_list))
            # 方式二
            # from django.forms.models import model_to_dict
            # publish_list = Publish.objects.all()
            # temp = []
            # for obj in publish_list:
            #     temp.append(model_to_dict(obj))
            # return HttpResponse(json.dumps(temp))
            # 方式三
            # from django.core import serializers
            # publish_list = Publish.objects.all()
            # temp = serializers.serialize("json",publish_list)
            # return HttpResponse(temp)
    
        def post(self, request):
            # 取数据
            # 原生的request操作
            # print('POST',request.POST)
            # print('body',request.body)
            # print(type(request))
            # from django.core.handlers.wsgi import WSGIRequest
            # print(request.data)
            # 新的request支持的操作
            # 要想使用之前request的方法
            # ret = request._request.POST
            # django将request的所有方法的数据获取进行了不同的封装
            # 而restframework将request下POST方法的数据封装成request.data
            # print('restframework',request.data)
            # print('restframework type',type(request.data))
            # return HttpResponse('post')
            ps = PublishModelSerializers(data=request.data)
            if ps.is_valid():
                print(ps.validated_data)
                ps.save()  # create方法
                return Response(ps.data)
            else:
                return Response(ps.errors)
    
    
    class PublishDetailView(APIView):
        def get(self, request, pk):
    
            publish = Publish.objects.filter(pk=pk).first()
            ps = PublishModelSerializers(publish)
            return Response(ps.data)
    
        def put(self, request, pk):
            publish = Publish.objects.filter(pk=pk).first()
            ps = PublishModelSerializers(publish, data=request.data)
            if ps.is_valid():
                ps.save()
                return Response(ps.data)
            else:
                return Response(ps.errors)
    
        def delete(self, request, pk):
            Publish.objects.filter(pk=pk).delete()
    
            return Response()
    view.py
    from rest_framework import serializers
    from .models import *
    
    # 为queryset,model对象做序列化
    # class PublishSerializers(serializers.Serializer):
    #     # 下面写的字段取决于你需要哪些字段做序列化
    #     name = serializers.CharField()
    #     email = serializers.CharField()
    
    class PublishModelSerializers(serializers.ModelSerializer):
        class Meta:
            model=Publish
            fields="__all__"
    
    
    class BookModelSerializers(serializers.ModelSerializer):
        class Meta:
            model = Book # 表名
            fields = "__all__" # 默认把所有字段写入,不包括自己写的get_authors方法
            # field = ['nid','title','authors','publish'] # 指定字段
            # exclude = ('nid')  # 除了...字段,不能跟fields同时用
            # depth = 1 #深度控制,写 几 往里拿几层,层数越多,响应越慢,官方建议0--10之间,个人建议最多3层
        # 如果要指定一对多,或多对多显示的字段需要重写create方法
        publish = serializers.CharField(source='publish.pk')
        authors = serializers.CharField(source="authors.all")
        def create(self, validated_data):
            # print('validated_data',validated_data)
            book = Book.objects.create(
                title=validated_data['title'],
                price=validated_data['price'],
                pub_date=validated_data['pub_date'],
                publish_id=validated_data['publish']['pk']
            )
            book.authors.add(*validated_data['authors'])
            return book
    all_serializers.py

    六、补充内容

    【get_xxx_display()方法】

    models.py

    ser.py

    这是个固定用法,打印看下结果

     【小技巧】

    可以使用https://www.json.cn来查看格式化的json

  • 相关阅读:
    完数
    自定义的allocator
    成绩的处理
    R语言-线性回归(1)
    R语言-朴素贝叶斯分类器(1)
    R语言控制流
    leetcode Two sum
    数据库环境搭建
    表单验证制作注册页面
    表单验证
  • 原文地址:https://www.cnblogs.com/neymargoal/p/9777322.html
Copyright © 2020-2023  润新知