• day 90 DjangoRestFramework学习二之序列化组件


     

    DjangoRestFramework学习二之序列化组件

     

    本节目录

    一 序列化组件

      首先按照restful规范咱们创建一些api接口,按照下面这些形式写吧:

        Courses --- GET ---> 查看数据----->返回所有数据列表[{},{},]

        Courses--- POST --->添加数据 -----> 返回添加的数据{ }

        courses/1 ---PUT---> 更新pk=1的数据 ----->返回更新后的数据{ }

        courses/1 --- DELETE---> 删除pk=1的数据 -----> 返回空

        courses/1 --- GET --->查看单条数据 -----> 返回单条数据 { }

      这样,我们先看一个drf给我们提供的一个类似于Postman功能的页面,首先我们创建一个django项目,创建一个Course表,然后添加一些数据,然后按照下面的步骤操作,

        第一步:引入drf的Response对象  

    复制代码
    from django.shortcuts import render,HttpResponse,redirect
    import json
    from django.views import View
    from app01 import models
    from rest_framework.views import APIView
    
    #引用drf提供的Response对象
    from rest_framework.response import Response
    
    #写我们的CBV视图 class CourseView(APIView):   #返回所有的Course数据 def get(self,request): course_obj_list = models.Course.objects.all() ret = [] for course_obj in course_obj_list: ret.append({ "title":course_obj.title, "desc":course_obj.desc, }) # return HttpResponse(json.dumps(ret, ensure_ascii=False)) return Response(json.dumps(ret, ensure_ascii=False)) #这里使用Response来返回消息 def post(self,request): print(request.data) return HttpResponse('POST')
    复制代码

        第二步:配置App,在我们的settings配置文件中配置

    复制代码
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01.apps.App01Config',
        'rest_framework',  #将它注册成App
    ]
    复制代码

        第三步,配置我们的路由

    复制代码
    """
    from django.conf.urls import url
    from django.contrib import admin
    from app01 import views
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^courses/', views.CourseView.as_view(),name='courses'),
    ]
    复制代码

        第四步:启动项目,通过浏览器访问我们的路由(必须是浏览器访问才能看到对应的功能),看效果:

          

        这里面我们可以发送不同类型的请求,看到对应的返回数据,类似于Postman,但是没有Postman好用,所以以后调试我们还是用Postman工具,但是我们知道一下昂。

      上面的数据,我们通过json自己进行的序列化,其实django也给我们提供了一个简单的序列化组件,看用法:

    复制代码
    from django.shortcuts import render,HttpResponse,redirect
    import json
    from django.views import View
    from app01 import models
    from rest_framework.views import APIView
    from django.core.serializers import serialize  #django的序列化组件,不是我们要学的drf的序列化组件昂
    
    #不用json自己来序列化了,太麻烦,我们使用drf提供的序列化组件
    from rest_framework.response import Response
    
    class CourseView(APIView):
    
        def get(self,request):
            course_obj_list = models.Course.objects.all()
            # ret = []
            # for course_obj in course_obj_list:
            #     ret.append({
            #         "title":course_obj.title,
            #         "desc":course_obj.desc,
            #     })
            # return HttpResponse(json.dumps(ret, ensure_ascii=False))
            # return Response(json.dumps(ret, ensure_ascii=False)
            se_data = serialize('json',course_obj_list,ensure_ascii=False)
            print(se_data)#也拿到了序列化之后的数据,简洁很多
            #[{"model": "app01.course", "pk": 1, "fields": {"title": "python", "desc": "666"}}, {"model": "app01.course", "pk": 2, "fields": {"title": "linux", "desc": "u4e5fu5f88u597d"}}, {"model": "app01.course", "pk": 3, "fields": {"title": "go", "desc": "u5c06u6765u53efu80fdu5f88u597d"}}]
    
            return Response(se_data)
    复制代码

      那么我们知道了两个序列化方式了,这个序列化是不是就简单很多啊,但是drf给我们做了一个更牛逼的序列化组件,功能更强大,而且不仅仅能做序列化,还能做其他的事情,所以呢,做api的时候,我们还是用drf提供的序列化组件。

    复制代码
    import json
    from datetime import datetime
    from datetime import date
    
    #对含有日期格式数据的json数据进行转换
    class JsonCustomEncoder(json.JSONEncoder):
        def default(self, field):
            if isinstance(field,datetime):
                return field.strftime('%Y-%m-%d %H:%M:%S')
            elif isinstance(field,date):
                return field.strftime('%Y-%m-%d')
            else:
                return json.JSONEncoder.default(self,field)
    
    
    d1 = datetime.now()
    
    dd = json.dumps(d1,cls=JsonCustomEncoder)
    print(dd)
    复制代码

      接下来重点到了,我们玩一下drf提供的数据序列化组件:

      1.我们通过GET方法,来查看所有的Course数据。

    复制代码
    from django.shortcuts import render,HttpResponse,redirect
    import json
    from django.views import View
    from app01 import models
    from rest_framework.views import APIView
    from django.core.serializers import serialize  #django的序列化组件,不是我们要学的drf的序列化组件昂
    
    from rest_framework.response import Response
    
    # 序列化方式3,1.引入drf序列化组件
    from rest_framework import serializers
    
    # 2.首先实例化一个类,继承drf的serializers.Serializer,类似于我们的form组件和models的用法
    class CourseSerializers(serializers.Serializer):
        #这里面也要写对应的字段,你写了哪些字段,就会对哪些字段的数据进行序列化,没有被序列化的字段,不会有返回数据,你可以注释掉一个,然后看返回的数据是啥
        title = serializers.CharField(max_length=32) #序列化的时候还能校验字段
        desc = serializers.CharField(max_length=32)
    
    class CourseView(APIView):
    
        def get(self,request):
            course_obj_list = models.Course.objects.all()
            # 3.使用我们创建的序列化类
            cs = CourseSerializers(course_obj_list, many=True)  # 序列化多个对象的时候,需要些many=True参数
            #4.通过返回对象的data属性就能拿到序列化之后的数据
            se_data = cs.data
            print(se_data) #[OrderedDict([('title', 'python'), ('desc', '666')]), OrderedDict([('title', 'linux'), ('desc', '也很好')]), OrderedDict([('title', 'go'), ('desc', '将来可能很好')])] 列表嵌套的有序字典。
    
            #还记得创建字典的另外一种写法吗?这个没啥用昂,给大家回顾一下之前的知识
            # d1 = {'name':'chao'}
            # d2 = dict([('name','chao'),('age',18)])
            # print(d1) #{'name': 'chao'}
            # print(d2) #{'age': 18, 'name': 'chao'}
            # # 有序字典
            # from collections import OrderedDict
            # d3 = OrderedDict([('name','Jaden'),('age',22)])
            # print(d3) #OrderedDict([('name', 'Jaden'), ('age', 22)])
    
            return Response(se_data) #drf的Response如果返回的是drf序列化之后的数据,那么客户端拿到的是一个有格式的数据,不再是一行显示了
    复制代码

       看效果:

        

      2.通过POST方法来添加一条数据:

    复制代码
    from django.shortcuts import render,HttpResponse,redirect
    from django.views import View
    from app01 import models
    from rest_framework.views import APIView
    
    from rest_framework.response import Response
    
    from rest_framework import serializers
    
    class CourseSerializers(serializers.Serializer):
        title = serializers.CharField(max_length=32)
        desc = serializers.CharField(max_length=32)
    
    class CourseView(APIView):
    
        def get(self,request):
            course_obj_list = models.Course.objects.all()
            cs = CourseSerializers(course_obj_list, many=True)
            se_data = cs.data
            return Response(se_data)
    
        def post(self,request):
            # print(request.data) #{'desc': 'java也挺好', 'title': 'java'}
            #发送过来的数据是不是要进行验证啊,drf的序列化组件还能校验数据
            cs = CourseSerializers(data=request.data,many=False) #注意必须是data=这种关键字参数,注意,验证单条数据的时候写上many=False参数,而且我们还要序列化这个数据,因为我们要给客户端返回这个数据
            # print(cs.is_valid()) #True ,如果少数据,得到的是False
            if cs.is_valid():
                print(cs.data)
                models.Course.objects.create(**cs.data)#添加数据
                return Response(cs.data) #按照post添加数据的api规则,咱们要返回正确的数据
            else:
                # 假如客户端发送过来的数据是这样的,少title的数据
                # {
                #     "desc": "java也挺好"
                # }
                cs_errors = cs.errors
                # print(cs_errors) #{'title': ['This field is required.']}
                return Response(cs_errors)
                # postman上我们看到的效果是下面这样的
                # {
                #     "title": [
                #         "This field is required."
                #     ]
                # }
    复制代码

      然后添加一些数据,好,接下来我们玩一些有关联关系的表

    复制代码
    class Author(models.Model): 
        nid = models.AutoField(primary_key=True)
        name=models.CharField( max_length=32)
        age=models.IntegerField()
    
    class AuthorDetail(models.Model):
    
        nid = models.AutoField(primary_key=True)
        birthday=models.DateField()
        telephone=models.BigIntegerField()
        addr=models.CharField( max_length=64)
    
    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()
    
    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=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE) #多对一到Publish表
        authors=models.ManyToManyField(to='Author',) #多对多到Author表
    复制代码

      看序列化代码: 

    复制代码
    from django.shortcuts import render,HttpResponse,redirect
    from django.views import View
    from app01 import models
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import serializers
    
    
    class BookSerializers(serializers.Serializer):
        #我们先序列化写两个字段的数据,别忘了这里面的字段和model表中的字段变量名要一样
        title = serializers.CharField(max_length=32)
        price = serializers.DecimalField(max_digits=5, decimal_places=2)
    
        #一对多的处理
        # publish = serializers.CharField(max_length=32)  #返回对象
        publish_email = serializers.CharField(max_length=32, source='publish.email')  # source指定返回的多对一的那个publish对象的email数据,并且我们现在找到书籍的email,所以前面的字段名称就可以不和你的publish对应好了,随便取名字
        publish_name = serializers.CharField(max_length=32, source='publish.email')  # source指定返回的多对一的那个publish对象的其他字段数据,可以接着写字段,也就是说关联的所有的字段的数据都可以写在这里进行序列化
    
        #对多对的处理
        # authors = serializers.CharField(max_length=32) #bookobj.authors拿到的类似于一个models.Authors.object,打印的时候这是个None
        # authors = serializers.CharField(max_length=32,source="authors.all") #这样写返回的是queryset类型的数据,这样给前端肯定是不行的,所以按照下面的方法写
        authors = serializers.SerializerMethodField() #序列化方法字段,专门给多对多字段用的,然后下面定义一个方法,方法名称写法是这样的get_字段名,名字必须是这样
        def get_authors(self,obj): #参数写一个obj,这个obj是一个一个的书籍对象,然后我们通过书籍对象来返回对应的数据
            # author_list_values = obj.authors.all().values() #返回这样类型的数据也行,那么具体你要返回什么结构的数据,需要和前端人员沟通清楚,然后这里对数据进行加工
            #假如加工成的数据是这种类型的[ {},{} ],就可以按照下面的逻辑来写,我简单写的,肯定有更好的逻辑来加工这些数据
            author_list_values = []
            author_dict = {}
            author_list = obj.authors.all()
            for i in author_list:
                author_dict['name'] = i.name
                author_list_values.append(author_dict)
            return author_list_values
    
    
    class BookView(APIView):
        def get(self,request):
            book_obj_list = models.Book.objects.all()
            s_books = BookSerializers(book_obj_list,many=True)
            return Response(s_books.data)
    
        def post(self,request):
            pass
    复制代码

      其实serializer在内部就做了这点事儿,伪代码昂。

        

      urls.py是这样写的:

    urlpatterns = [
        #url(r'^admin/', admin.site.urls),
        #做一些针对书籍表的接口
        url(r'^books/', views.BookView.as_view(),),
    
    ]

       然后看Postman返回的数据:

        

      那么我们就能够完成各种数据的序列化了,但是你会发现,这样写太累啦,这只是一张表啊,要是上百张表咋整啊,所以还有一个更简单的方式(类似于form和modelform的区别)。

      我们使用ModelSerializer,看代码:

    复制代码
    #ModelSerializer
    class BookSerializers(serializers.ModelSerializer):
        class Meta:
            model=models.Book
            # fields=['title','price','publish','authors']
            fields = "__all__"
            # 如果直接写all,你拿到的数据是下面这样的,但是如果人家前端和你要的作者的id和名字,你是不是要处理一下啦
            # [
            #     {
            #         "nid": 3,
            #         "title": "go",
            #         "publishDate": null,
            #         "price": "122.00",
            #         "publish": 2,
            #         "authors": [
            #             2,
            #             1
            #         ]
            #     }
            # ]
        #那么没办法,只能自己再进行加工处理了,按照之前的方式
        authors = serializers.SerializerMethodField()
        def get_authors(self,obj):
            author_list_values = []
            author_dict = {}
            author_list = obj.authors.all()
            for i in author_list:
                author_dict['id'] = i.pk
                author_dict['name'] = i.name
                author_list_values.append(author_dict)
            return author_list_values #这个数据就会覆盖上面的序列化的authors字段的数据
        # 那么前端拿到的数据就这样了
        # [
        #     {
        #         "nid": 3,
        #         "authors": [
        #             {
        #                 "name": "chao",
        #                 "id": 1
        #             },
        #             {
        #                 "name": "chao",
        #                 "id": 1
        #             }
        #         ],
        #         "title": "go",
        #         "publishDate": null,
        #         "price": "122.00",
        #         "publish": 2
        #     }
        # ]
        # 那如果一对多关系的那个publish,前端想要的数据是名字怎么办呢?还是老办法,source
        # publish_name = serializers.CharField(max_length=32, source='publish.name')#但是你会发现序列化之后的数据有个publish:1对应个id值,如果我不想要他怎么办,那么可以起个相同的变量名来覆盖它,比如下面的写法
        publish = serializers.CharField(max_length=32, source='publish.name')
    
    class BookView(APIView):
        def get(self,request):
            book_obj_list = models.Book.objects.all()
            s_books = BookSerializers(book_obj_list,many=True)
            return Response(s_books.data)
    
        def post(self,request):
            pass
    复制代码

      上面我们完成了get请求来查看所有的书籍信息,接下来我们玩一个post请求添加一条book数据,直接上代码吧:

    复制代码
    class BookSerializers(serializers.ModelSerializer):
        class Meta:
            model=models.Book
            fields = "__all__"
       # 注意先把下面这些注释掉
        # authors = serializers.SerializerMethodField()
        # def get_authors(self,obj):
        #     author_list_values = []
        #     author_dict = {}
        #     author_list = obj.authors.all()
        #     for i in author_list:
        #         author_dict['id'] = i.pk
        #         author_dict['name'] = i.name
        #         author_list_values.append(author_dict)
        #     return author_list_values
        # publish = serializers.CharField(max_length=32, source='publish.name')
    
    class BookView(APIView):
        def get(self,request):
            book_obj_list = models.Book.objects.all()
            s_books = BookSerializers(book_obj_list,many=True)
            return Response(s_books.data)
    
    
        def post(self,request):
    
            b_serializer = BookSerializers(data=request.data,many=False)
            if b_serializer.is_valid():
                print('xxxx')
                b_serializer.save() #因为这个序列化器我们用的ModelSerializer,并且在BookSerializers类中我们指定了序列化的哪个表,所以直接save,它就知道我们要将数据保存到哪张表中,其实这句话执行的就是个create操作。
                return Response(b_serializer.data) #b_serializer.data这就是个字典数据
    
            else:
                return Response(b_serializer.errors)
    复制代码

      上面我们完成了GET和POST请求的接口写法,下面我们来完成PUT、DELETE、GET查看单条数据的几个接口。

      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'^courses/', views.CourseView.as_view()),
        #做一些针对书籍表的接口
        #GET和POST接口的url
        url(r'^books/$', views.BookView.as_view(),), #别忘了$符号结尾
    
        #PUT、DELETE、GET请求接口
        url(r'^books/(d+)/', views.SBookView.as_view(),),
    
    ]
    复制代码

      views.py代码如下:

    复制代码
    from django.shortcuts import render,HttpResponse,redirect
    from django.views import View
    from app01 import models
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import serializers
    
    class BookSerializers(serializers.ModelSerializer):
        class Meta:
            model=models.Book
            fields = "__all__"
    
    class BookView(APIView):
        def get(self,request):
            '''
            查看所有书籍
            :param request:
            :return:
            '''
            book_obj_list = models.Book.objects.all()
            s_books = BookSerializers(book_obj_list,many=True)
            return Response(s_books.data)
    
        def post(self,request):
            '''
            添加一条数据
            :param request:
            :return:
            '''
            b_serializer = BookSerializers(data=request.data,many=False)
            if b_serializer.is_valid():
                b_serializer.save()
                return Response(b_serializer.data)
            else:
                return Response(b_serializer.errors)
    
    #因为更新一条数据,删除一条数据,获取一条数据,都有个单独的参数(获取一条数据的,一般是id,所以我将put、delete、get写到了一个视图类里面,也就是说结合上面那个BookView视图类,完成了我们的那些接口)
    class SBookView(APIView):
        def get(self,request,id):
            '''
            获取单条数据
            :param request:
            :param id:
            :return:
            '''
            book_obj = models.Book.objects.get(pk=id)#获取这条数据对象
            #接下来序列化单个model对象,序列化单个对象返回的是一个字典结构 {},序列化多个对象返回的是[{},{}]这种结构
            book_serializer = BookSerializers(book_obj,many=False)
            return Response(book_serializer.data)
    
    
        def put(self,request,id):
            '''
            更新一条数据
            :param request:request.data更新提交过来的数据
            :param id:
            :return:
            '''
            book_obj = models.Book.objects.get(pk=id)
            b_s = BookSerializers(data=request.data,instance=book_obj,many=False) #别忘了写instance,由于我们使用的ModelSerializer,所以前端提交过来的数据必须是所有字段的数据,当然id字段不用
            if b_s.is_valid():
                b_s.save() #翻译成的就是update操作
                return Response(b_s.data) #接口规范要求咱们要返回更新后的数据
            else:
                return Response(b_s.errors)
    
        def delete(self,request,id):
            '''
            删除一条数据
            :param request:
            :param id:
            :return:
            '''
            book_obj = models.Book.objects.get(pk=id).delete()
            return Response("") #别忘了接口规范说最好返回一个空
    复制代码

      好,五个接口写完,咱们的序列化组件就算是讲完了。

    二 xxx

      

    三 xxx

    四 xxx

    五 xxx

    六 xxx

    七 xxx

    八 xxx

      

  • 相关阅读:
    linux中iptables的用法
    Git介绍及安装配置
    第一个shell脚本
    Nginx配置优化解读
    Python中print格式化输出
    python 程序构架浅析
    Python 常用字符串操作
    Python入门学习:网络刷博器爬虫
    vSphere SDK for Java
    vROPS中获取虚拟机在VC中的UUID
  • 原文地址:https://www.cnblogs.com/yanghongtao/p/10729515.html
Copyright © 2020-2023  润新知