• DRF序列化


    Serializers 序列化组件

    什么要用序列化组件 :

      在我们做前后端分离的项目时候, 我们前后端交互一般都选择JSON数据格式, JSON是一个轻量级的数据交互格式.

      那么我们给前端数据的时候都要转成JSON格式, 那就需要对我们从数据库拿到的数据进行序列化.

      


    Django的序列化方法 :

    class BooksView(View):
        def get(self, request):
            book_list = Book.objects.values("id", "title", "chapter", "pub_time", "publisher")
            book_list = list(book_list)
            # 如果我们需要取外键关联的字段信息 需要循环获取外键 再去数据库查然后拼接成我们想要的
            ret = []
            for book in book_list:
                pub_dict = {}
                pub_obj = Publish.objects.filter(pk=book["publisher"]).first()
                pub_dict["id"] = pub_obj.pk
                pub_dict["title"] = pub_obj.title
                book["publisher"] = pub_dict
                ret.append(book)
            ret = json.dumps(book_list, ensure_ascii=False, cls=MyJson)
            return HttpResponse(ret)
    
    
    # json.JSONEncoder.default()
    # 解决json不能序列化时间字段的问题
    class MyJson(json.JSONEncoder):
        def default(self, field):
            if isinstance(field, datetime.datetime):
                return field.strftime('%Y-%m-%d %H:%M:%S')
            elif isinstance(field, datetime.date):
                return field.strftime('%Y-%m-%d')
            else:
                return json.JSONEncoder.default(self, field)
    .value序列化结果
    from django.core import serializers
    
    
    # 能够得到我们要的效果 结构有点复杂
    class BooksView(View):
        def get(self, request):
            book_list = Book.objects.all()
            ret = serializers.serialize("json", book_list)
            return HttpResponse(ret)
    django serializers 序列化

    DRF序列化方法 :

    想要使用DRF的序列化, 就要遵循人家框架的一些标准 :

      -Django 中CBV继承类时View, 现在DRF要继承APIView

      -Django 中返回的时候我们用HTTPResponse, JsonResponse, reder, 而DRF我们使用Response来接受.

    序列化 :

    class Book(models.Model):
        title = models.CharField(max_length=32)
        CHIOCES = ((1, "python"), (2, "linux"), (3, "go"))
        category = models.IntegerField(choices=CHIOCES)
        pub_time = models.DateField()
        publisher = models.ForeignKey(to="Publisher")
        author = models.ManyToManyField(to="Author")
    mdoel表的字段
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)  # required 为False时, 反序列化不做校验
        title = serializers.CharField(max_length=32, validators=[my_validate])
        pub_time = serializers.DateField()
        CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
        category = serializers.CharField(choices=CHOICES)
    
        publisher = PublisherSerializer(read_only=True)
        # 多对多有many参数
        author = AuthorSerializer(many=True, read_only=True)
    声明序列化器
    from rest_framework.views import APIView
    from app01 import models
    from .serializers import BookSerializer
    from rest_framework.response import Response
    
    class BookView(APIView):
        def get(self, request):
            book_queryset = models.Book.objects.all()
            # 用序列化器进行序列化
            ser_obj = BookSerializer(book_queryset, many=True)
    
            return Response(ser_obj.data)
    序列化对象

    外键关系的序列化 :

    from rest_framework import serializers
    from app01 import models
    
    
    class PublisherSerializer(serializers.Serializer):
        id = serializers.IntegerField()
        title = serializers.CharField(max_length=32)
    
    
    class AuthorSerializer(serializers.Serializer):
        id = serializers.IntegerField()
        name = serializers.CharField(max_length=32)
    
    
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(read_only=True)
        title = serializers.CharField(max_length=32)
        CHOICES = ((1, "Linux"), (2, "Django"), (3, "Python"))
        chapter = serializers.ChoiceField(choices=CHOICES, )
        pub_time = serializers.DateField()
    
        publisher = PublisherSerializer(read_only=True)
        # 多对多字段有many=True参数
        author= AuthorSerializer(many=True, read_only=True)
    外键关系的序列化器

    反序列化 :

      当前端给我们发送post请求时候, 前端给我们传来的数据, 我们要经过一些校验然后保存到数据库. 这些校验以及爆粗工作, DRF的serializer也给我们提供了一些方法了.

      首先, 我们要写反序列化需要使用的一些字段, 有些字段(外键, 多对多, choices)需要和序列化字段分开.

      serializer提供了 .is_valid() 和 .save()方法

    from django.db import models
    
    
    class Book(models.Model):
        title = models.CharField(max_length=32)
        CHIOCES = ((1, "python"), (2, "linux"), (3, "go"))
        category = models.IntegerField(choices=CHIOCES)
        pub_time = models.DateField()
        publisher = models.ForeignKey(to="Publisher")
        author = models.ManyToManyField(to="Author")
    
    
    class Publisher(models.Model):
        title = models.CharField(max_length=32)
    
    
    class Author(models.Model):
        name = models.CharField(max_length=32)
    全部model
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)  # required 为False时, 反序列化不做校验
        title = serializers.CharField(max_length=32, validators=[my_validate])
        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)
        publisher_id = serializers.IntegerField(write_only=True)
        # 多对多有many参数
        author = AuthorSerializer(many=True, read_only=True)
        author_list = serializers.ListField(write_only=True)
    
        # 新增数据要重写的create方法
        def create(self, validated_data):
            # validated_data是验证通过的数据
            # 通过ORM操作给Book表增加数据
            # 添加除多对多字段的所有字段
            book_obj = models.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.author.add(*validated_data["author_list"])
            return book_obj
    反序列化序列化器
    class BookView(APIView):
        def get(self, request):
            book_queryset = models.Book.objects.all()
            # 用序列化器进行序列化
            ser_obj = BookSerializer(book_queryset, many=True)
    
            return Response(ser_obj.data)
    
        def post(self, request):
            # 接收前端传过来的数据
            book_obj = request.data
            # 对前端传过来的数据使用自定义序列化方法进行校验(是否合法等)
            ser_obj = BookSerializer(data=book_obj)
            # 如果校验通过做些什么
            if ser_obj.is_valid():
                ser_obj.save()
                # validated_data是校验通过之后的数据
                return Response(ser_obj.validated_data)
            # 验证不通过返回错误信息
            return Response(ser_obj.errors)
    反序列化view.py

      当前端给我们发送put或者delete请求的时候, 前端给我们用户需要更新的数据, 我们要对数据进行部分验证.

    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)  # required 为False时, 反序列化不做校验
        title = serializers.CharField(max_length=32, validators=[my_validate])
        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)
        publisher_id = serializers.IntegerField(write_only=True)
        # 多对多有many参数
        author = AuthorSerializer(many=True, read_only=True)
        author_list = serializers.ListField(write_only=True)
    
        # 新增数据要重写的create方法
        def create(self, validated_data):
            # validated_data是验证通过的数据
            # 通过ORM操作给Book表增加数据
            # 添加除多对多字段的所有字段
            book_obj = models.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.author.add(*validated_data["author_list"])
            return book_obj
    
        # 更新数据要重写update方法
        def update(self, instance, validated_data):
            # instance 是要更新的对象
            # 对除多对多字段以外的字段进行更新, 并设置当前已存在的数据为默认值
            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)
            # 判断前端传过来的数据是否含有author_list字段, 如果有则更新, 没有就不变动
            if validated_data.get("author_list"):
                instance.author.set(validated_data["author_list"])
            instance.save()
            return instance
    put或者delete的序列化器
    from rest_framework.views import APIView
    from app01 import models
    from .serializers import BookSerializer
    from rest_framework.response import Response
    
    class BookEditView(APIView):
        def get(self, request, edit_id):
            book_obj = models.Book.objects.filter(id=edit_id).first()
            ser_obj = BookSerializer(book_obj)
            return Response(ser_obj.data)
    
        def put(self, request, edit_id):
            book_obj = models.Book.objects.filter(id=edit_id).first()
            ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
            if ser_obj.is_valid():
                ser_obj.save()
                return Response(ser_obj.validated_data)
            return Response(ser_obj.errors)
    
        def delete(self, request, edit_id):
            book_obj = models.Book.objects.filter(id=edit_id).first()
            if not book_obj:
                return Response("删除对象不存在!")
            book_obj.delete()
            return Response("删除成功了呢!")
    put或者delete的view.py

    验证 :

      如果我们需要对一些字段进行自定义的验证, DRF也给我们提供了钩子方法.

    def my_validate(value):
        if "敏感信息" in value.lower():
            raise serializers.ValidationError("存在敏感词汇!!!")
    
    
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)  # required 为False时, 反序列化不做校验
        title = serializers.CharField(max_length=32, validators=[my_validate])
    自定义验证器
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(read_only=True)
        title = serializers.CharField(max_length=32)
        # 省略了一些字段 跟上面代码里一样的
        # 。。。。。
         def validate_title(self, value):
            if "python" not in value.lower():
                raise serializers.ValidationError("标题必须含有Python")
            return value
    单个字段的验证
     class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)  # required 为False时, 反序列化不做校验
        title = serializers.CharField(max_length=32, validators=[my_validate])
        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)
        publisher_id = serializers.IntegerField(write_only=True)
        # 多对多有many参数
        author = AuthorSerializer(many=True, read_only=True)
        author_list = serializers.ListField(write_only=True)
    
    
    
    
    # 对前端传过来的数据进行条件控制
    def validate(self, attrs):
          # 相当于钩子函数
          # attrs是一个字典, 含有传过来的所有字段
           if "python" in attrs["title"].lower() and attrs["post_category"] == 1:
               return attrs
           else:
               raise serializers.ValidationError("分类或标题不匹配")
    多个字段的验证

    ModelSerizlizer :

    当我们清楚了Srrializer的用法之后, 会发现所有的序列化跟我们的模型都紧密相关.

    既然如此, DRF也给我们提供了跟模型紧密相关的序列化器: ModelSerializer

      此序列化器会根据模型自动生成一组字段

      并且简单的默认实现了 .update()以及 .create()方法

    定义一个ModelSerializer序列化器 :

    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = Book
            fields = "__all__"
            # fields = ["id", "title", "pub_time"]
            # exclude = ["user"]
            # 分别是所有字段 包含某些字段 排除某些字段

    外键关系的序列化 :

      ※. 当序列化类MATE中定义了depth时, 这个序列化类中引用字段(外键)则自动变为只读.

    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = Book
            fields = "__all__"
            # fields = ["id", "title", "pub_time"]
            # exclude = ["user"]
            # 分别是所有字段 包含某些字段 排除某些字段
            depth = 1
    # depth 代表找嵌套关系的第几层

    自定义字段 :

      可以通过声明字段的防水来覆盖默认字段, 来进行自定制

      比如model中的choices字段, 默认显示的是选择的key, 而要展示给用户的是value

    class BookSerializer(serializers.ModelSerializer):
        chapter = serializers.CharField(source="get_chapter_display", read_only=True)
        
        class Meta:
            model = Book
            fields = "__all__"
            # fields = ["id", "title", "pub_time"]
            # exclude = ["user"]
            # 分别是所有字段 包含某些字段 排除某些字段
            depth = 1

    Meta中的其他关键字参数 :

    class BookSerializer(serializers.ModelSerializer):
        """
        继承ModelSerializer方法不需要在定义一个用来反序列化的字段
        """
    
        # 以下方法为自定义外键, 多对多, choices字段的显示内容
    
        # 根据自己方法里构建的数据返回给指定的字段, 钩子函数返回什么就展示什么
        publisher_info = serializers.SerializerMethodField(read_only=True)
        author_info = serializers.SerializerMethodField(read_only=True)
        category_info = serializers.SerializerMethodField(read_only=True)
    
        # SerializerMethodField提供的钩子函数, get_使用钩子函数的字段名
        # 此钩子函数的返回值会返回给SerializerMethodField方法
        # obj参数为调用序列化方法的QuerySet中的每个对象
        def get_publisher_info(self, obj):
            # publisher_query为每个序列化对象所关联的外键对象
            publisher_query = obj.publisher
            return {"id": publisher_query.id, "title": publisher_query.title}
        def get_author_info(self, obj):
            # author_query为每个要序列化对象所关联的多对多的全部对象
            author_query = obj.author.all()
            return [{"id": author.id, "name": author.name} for author in author_query]
        # choices字段, 将要序列化的对象直接调用一次display方法, 使其显示具体内容即可
        def get_category_info(self, obj):
            return obj.get_category_display()
    
    
        class Meta:
            model = models.Book
            fields = "__all__"
            # "depth解释  ↓↓↓"
            # 会查找一层外键关联的对象的所有(划重点)字段内容
            # 但会使这些所有的外键关系变成read_only = True, 反序列化外键关系会丢失
            # 一般情况下不常用
            # depth = 1
    
            # 加自定义操作的方法
            # 使publisher, author字段添加一个write_only参数, 是其只能进行反序列化使用
            extra_kwargs = {"publisher": {"write_only": True}, "author": {"write_only": True}, "category": {"write_only": True}}

      

  • 相关阅读:
    SQL Server 隐式转换引发的死锁
    C# List按某对象的属性分组 IGrouping
    C# 正则表达式获取json字符串中的键值
    .NET程序修改 ConfigurationManager 后,不需要重启IIS也可刷新Web.config配置文件
    相同结构的多个表合并到一个表的实现方法
    WCF系列_WCF影响客户端导出Excel文件的实现
    WCF系列_WCF如何选择不同的绑定
    WCF系列_WCF常用绑定选择
    JS生成URL二维码
    win 常用CMD命令备忘
  • 原文地址:https://www.cnblogs.com/dong-/p/9971915.html
Copyright © 2020-2023  润新知