zoukankan      html  css  js  c++  java
  • DRF--序列化

    为什么要用序列化

    当我们做前后端分离的项目时,前后端交互一般都是JSON格式的数据,那么我们给前端的数据就要转为JSON格式,就需要我们拿到数据库后的数据进行序列化。在看DRF的序列化之前,先来看看django的序列化

    from django.db import models
    
    # Create your models here.
    
    __all__ = ["Book", "Publisher", "Author"]
    
    
    class Book(models.Model):
        title = models.CharField(max_length=32)
        CHOICES = ((1, "python"), (2, "Liunux"), (3, "Go"))
        category = models.IntegerField(choices=CHOICES)
        pub_time = models.DateField()
        publisher = models.ForeignKey(to="Publisher")
        authors = models.ManyToManyField(to="Author")
    
    
    class Publisher(models.Model):
        title = models.CharField(max_length=32)
    
        def __str__(self):
            return self.title
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
    
        def __str__(self):
            return self.name
    model.py
    from django.http import JsonResponse
    from django.shortcuts import render
    from django.views import View
    from djangoDemo.models import Book, Publisher
    
    
    # 第一版用values方法取数据
    class BookView(View):
        def get(self, request):
            book_queryset = Book.objects.values("id", "title", "pub_time", "publisher")
            book_list = list(book_queryset)
            ret = []
            for book in book_list:
                book["publisher"] = {
                    "id": book["publisher"],
                    "title": Publisher.objects.filter(id=book["publisher"]).first().title,
                }
                ret.append(book)
            # ret = json.dumps(book_list, ensure_ascii=False)
            # return HttpResponse(ret)
            return JsonResponse(ret, safe=False, json_dumps_params={"ensure_ascii": False})
    序列化

    DRF的序列化

    从上面的例子中可以看出来,这样我们序列化出来的数据,写法很麻烦。所以我们用DRF的序列化,要用别人的序列化就要遵守别人的规则,首先需要在app里注册

    INSTALLED_APPS = [
        'django.contrib.admin',
    
        ...
        
        'rest_framework',
    ]

    注册好了之后要声明序列化类,在当前app下创建一个py文件

     1 from rest_framework import serializers
     2 
     3 #  出版社的序列化器,前面的变量要和model里的变量名一样
     4 class PublisherSerializer(serializers.Serializer):
     5     id = serializers.IntegerField()
     6     title = serializers.CharField(max_length=32)
     7 
     8 
     9 class AuthorSerializer(serializers.Serializer):
    10     id = serializers.IntegerField()
    11     name = serializers.CharField(max_length=32)
    12 
    13 
    14 class BookSerializer(serializers.Serializer):
    15     id = serializers.IntegerField()
    16     title = serializers.CharField(max_length=32)
    17     pub_time = serializers.DateField()
    18     category = serializers.CharField(source="get_category_display")  # 选择的需要指定source
    19 
    20     publisher = PublisherSerializer()  # 一对多的表
    21     authors = AuthorSerializer(many=True)  # 多对多的表需要指定many=True

    上面我们就写好了序列化的类,注意:匹配上的字段进行序列化,匹配不上则丢弃,所以前端需要哪些字段就写哪些,如果不写的就不序列化

    外键关系的序列化是嵌套的序列化器对象 
    注意many=True

    然后再视图函数里写序列化对象

    from django.shortcuts import render
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from djangoDemo.models import Book  # 导入表
    from .serializers import BookSerializer
    
    
    class BookView(APIView):
        def get(self, request):
            book_queryset = Book.objects.all()
            # 拿出来的是一个queryset,用序列化器进行序列化
            ser_obj = BookSerializer(book_queryset, many=True)
            return Response(ser_obj.data)  # 序列化后的数据在data里

    注意:当查询出的数据是一个queryset时,需要加many=True,内部会认为是一个可迭代的对象,会去循环。当查询出的是一条数据时,不需要加many=True,会报错

    当我们访问这个接口时,返回的数据就是如下的格式

    {
            "id": 1,
            "title": "python从入门到放弃",
            "pub_time": "2019-09-10",
            "category": "python",
            "publisher": {
                "id": 1,
                "title": "清华"
            },
            "authors": [
                {
                    "id": 1,
                    "name": "马云"
                },
                {
                    "id": 2,
                    "name": "刘亦菲"
                }
            ]
        }

    反序列化

    当我们进行post请求的时候,我们需要定义数据格式,然后让前端的妹子传给我们对应的格式。格式确定之后我们还要校验前端妹子传过来的格式和字段,比如字段的类型还有长度,我们不能相信前端妹子的话,妹子说“我没事”。难道就真没事了吗?所以数据校验是必不可少的。

    数据格式当然是json格式的,那怎么校验数据呢,在上面我们写了个序列化类,来序列化返回给前端的数据,我们也可以用来校验前端传给我们的数据。因为id是自动递增的,所以前端不需要传,我们也不需要校验,可以加个参数required=False,表示只序列化不反序列化。还有些字段,比如上面的category字段,我们序列化的时候返回的是后面的汉字,而反序列化的时候,我们希望是前面的数字,所以我们需要重写这个字段,如果字段里有read_only=True,表示只序列化。如果是write_only=True,表示只反序列化

    返回的数据是上面格式的,我们如果新增数据,希望数据是下面这个格式的

    {
          
            "title": "HTML",
            "pub_time": "2019-09-10",
            "post_category": 1,
            "publisher_id":1,
            "author_list": [1,2]
    }

    注意,前面的key是序列化器里对应的字段

    先来改写序列化器

    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)  # 只序列化,不走校验
        title = serializers.CharField(max_length=32)
        pub_time = serializers.DateField()
        category = serializers.CharField(source="get_category_display", read_only=True)  # 只序列化用
        # 因为前端传的是数字,所以需要重写
        post_category = serializers.IntegerField(write_only=True)  # 只反序列化用
    
        publisher = PublisherSerializer(read_only=True)  # 一对多的表  只序列化用
        authors = AuthorSerializer(many=True, read_only=True)  # 多对多的表需要指定many=True 只序列化用
    
        publisher_id = serializers.IntegerField(write_only=True)  # 只反序列化用
        author_list = serializers.ListField(write_only=True)  # 只反序列化用
    
        def create(self, validated_data):
            # validated_data校验通过的数据
            # 通过ORM操作给book表增加数据
            book_obj = Book.objects.create(title=validated_data['title'],
                                           pub_time=validated_data['pub_time'],
                                           category=validated_data['post_category'],
                                           publisher_id=validated_data['publisher_id'])
            book_obj.authors.add(*validated_data['author_list'])  # 这个参数可能是一个列表
            return book_obj

    在来改写视图函数,新增post请求

    class BookView(APIView):
        def get(self, request):
            book_queryset = Book.objects.all()
            # 拿出来的是一个queryset,用序列化器进行序列化
            ser_obj = BookSerializer(book_queryset, many=True)
            return Response(ser_obj.data)  # 序列化后的数据在data里
    
        def post(self, request):
            # 确定数据类型以及数据结构
            # 对前端传来的数据进行校验
            book_obj = request.data  # post传来的数据
            ser_obj = BookSerializer(data=book_obj) # 有data参数,表示反序列化
            if ser_obj.is_valid():
                ser_obj.save()
                return Response(ser_obj.validated_data)
            return Response(ser_obj.errors)  # 返回错误

    这样,当我们提交像上面一样的数据格式之后,在看get请求,就返回如下的数据

    [
        {
            "id": 1,
            "title": "python从入门到放弃",
            "pub_time": "2019-09-10",
            "category": "python",
            "publisher": {
                "id": 1,
                "title": "清华"
            },
            "authors": [
                {
                    "id": 1,
                    "name": "马云"
                },
                {
                    "id": 2,
                    "name": "刘亦菲"
                }
            ]
        },
        {
            "id": 2,
            "title": "Linux跑路",
            "pub_time": "2019-09-18",
            "category": "Liunux",
            "publisher": {
                "id": 2,
                "title": "北大"
            },
            "authors": [
                {
                    "id": 2,
                    "name": "刘亦菲"
                }
            ]
        },
        {
            "id": 3,
            "title": "HTML",
            "pub_time": "2019-09-10",
            "category": "python",
            "publisher": {
                "id": 1,
                "title": "清华"
            },
            "authors": [
                {
                    "id": 1,
                    "name": "马云"
                },
                {
                    "id": 2,
                    "name": "刘亦菲"
                }
            ]
        }
    ]
    序列化返回给前端的数据

    put反序列化

     上面的序列化是post请求的,那我们修改数据的时候可能是只对某一个字段进行修改

    路由:

    urlpatterns = [
        url(r'^book/$', BookView.as_view()),
        url(r'^book/(?P<id>d+)', BookEditView.as_view()),
    ]

    在 BookSerializer 序列化类里添加一个update方法

    def update(self, instance, validated_data):
        # instance 更新的book_obj对象
        # validated_data 校验通过的数据
        instance.title = validated_data.get("title",instance.title)
        instance.pub_time = validated_data.get("pub_time",instance.pub_time)
        instance.category = validated_data.get("post_category",instance.category)
        instance.publisher_id = validated_data.get("publisher_id",instance.publisher_id)
        if validated_data.get("author_list"):  # 可能有多个值
            instance.author.set(validated_data["author_list"])
        instance.save()  # 保存
        return instance

    因为不知道修改的是哪个字段,所以都要写

    在写put请求

    class BookEditView(APIView):
        def get(self, request, id):
            book_obj = Book.objects.filter(id=id).first()
            ser_obj = BookSerializer(book_obj)  # 查询出的是一条数据,不需要加 many=True
            return Response(ser_obj.data)
    
        def put(self, request, id):
            book_obj = Book.objects.filter(id=id).first()
            # instance必传,data=request.data前端传的参数,partial=True部分修改
            ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
            if ser_obj.is_valid():
                ser_obj.save()
                return Response(ser_obj.data)  # 返回数据,注意不是ser_obj.validated_data
            return Response(ser_obj.errors)
  • 相关阅读:
    环形链表II 找环入口
    最短无序连续子数组 复制数组排序后与原数组相比
    和为K的子数组 暴力 或 hash+前缀
    在排序数组中查找元素的第一个和最后一个位置 二分法+递归
    NodeJs 批量重命名文件,并保存到指定目录
    NodeJs 批量图片瘦身,重设尺寸和图片质量并保存到指定目录
    NodeJs 获取照片拍摄日期和视频拍摄日期,并按日期目录存档
    Oracle迁移记录
    Oracle数据库迁移前的准备工作(创建用户并且分配权限及表空间)
    Oracle 11g R2性能优化 10046 event【转载】
  • 原文地址:https://www.cnblogs.com/zouzou-busy/p/11559739.html
Copyright © 2011-2022 走看看