zoukankan      html  css  js  c++  java
  • 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}}

      

  • 相关阅读:
    JavaScript cookie详解
    Javascript数组的排序:sort()方法和reverse()方法
    javascript中write( ) 和 writeln( )的区别
    div做表格
    JS 盒模型 scrollLeft, scrollWidth, clientWidth, offsetWidth 详解
    Job for phpfpm.service failed because the control process exited with error code. See "systemctl status phpfpm.service" and "journalctl xe" for details.
    orm查询存在价格为空问题
    利用救援模式破解系统密码
    SSH服务拒绝了密码
    C# 调用 C++ DLL 中的委托,引发“对XXX::Invoke类型的已垃圾回收委托进行了回调”错误的解决办法
  • 原文地址:https://www.cnblogs.com/dong-/p/9971915.html
Copyright © 2011-2022 走看看