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

    一、安装 Django REST framework 框架

    使用命令:pip install djangorestframework

    二、在setings里面注册

    INSTALLED_APPS = [
    "rest_framework"
    ]

    Serializers 序列化组件

    为什么要用序列化组件

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

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

    Django的序列化方法

    from django.shortcuts import render
    from django.views import View
    from django.http import HttpResponse, JsonResponse
    from .models import Book, Publisher
    from django.core import serializers
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import serializers
    from .serializers import BookSerializer
    import json
    
    class BookView(View):
    第一版用.values实现序列化
    def get(self, request):
        book_queryset = Book.objects.values("id", "title", "pub_time", "publisher")
        # queryset [{}, {}]
        book_list = list(book_queryset)
        ret = json.dumps(book_list, ensure_ascii=False)#无法序列化datetime数据类型
    return HttpResponse(ret)
        ret = []
        for book in book_list:
            publisher_obj = Publisher.objects.filter(id=book["publisher"]).first()
            book["publisher"] = {
                "id": publisher_obj.id,
                "title": publisher_obj.title
            }
            ret.append(book)
        return JsonResponse(ret, safe=False, json_dumps_params={"ensure_ascii": False})#注意和json.dumps的ensure_ascii区别
    
    第二版 用Django自带的序列化模块依然无法完成序列化外键关系,只能序列化模型
    def get(self, request):
        book_queryset = Book.objects.all()
        ret = serializers.serialize("json", book_queryset, ensure_ascii=False)
        return HttpResponse(ret)

    DRF序列化的方法

    首先,我们要用DRF的序列化,就要遵循人家框架的一些标准,

      -- Django我们CBV继承类是View,现在DRF我们要用APIView

      -- Django中返回的时候我们用HTTPResponse,JsonResponse,render ,DRF我们用Response

    序列化

    from rest_framework import serializers
    from .models import Book
    
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)#这个字段不需要校验
        title = serializers.CharField(max_length=32)
        pub_time = serializers.DateField()
        # CHOICES = ((1, "python"), (2, "linux"), (3, "go"))
        # category = serializers.ChoiceField(choices=CHOICES)
        #"get_category_display"显示对应序号的中文
        category = serializers.CharField(source="get_category_display", read_only=True)#注意ChoiceField改成CharField,这个字段正序用
        post_category = serializers.IntegerField(write_only=True)#这个字段只反序用
        
        publisher = PublisherSerializer(read_only=True)
        authors = AuthorSerializer(many=True, read_only=True)#author和book是多对多关系,所以many=True
    
        publisher_id = serializers.IntegerField(write_only=True)
        author_list = serializers.ListField(write_only=True)
    
    
        def create(self, validated_data):
            #通过ORM操作给Book表增加数据
            print(validated_data)#字典类型
            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"])#多对多不需要save
            return book_obj
    class BooksView(APIView):
        def get(self, request):
            # print(request._request)
            book_queryset = Book.objects.all()
            # 声明一个序列化器
            # 用序列化器去序列化queryset
            ser_obj = BookSerializer(book_queryset, many=True)  # 如果是多个book_queryset必须声明:many=True
            # 序列化好的数据在data里面
            return Response(ser_obj.data)
    APIView和View区别
       -- APIView继承了View
       -- 豁免csrf
       -- 封装了request 用Request
       -- _request是旧的request
       -- request.query_params == _request.GET
       -- request.data == _request.POST _request.Files 除了GET的所有的信息

    反序列化

    当前端给我们发post的请求的时候~前端给我们传过来的数据~我们要进行一些校验然后保存到数据库~

    这些校验以及保存工作,DRF的Serializer也给我们提供了一些方法了~~

    首先~我们要写反序列化用的一些字段~有些字段要跟序列化区分开~~

    Serializer提供了.is_valid()  和.save()方法~~

    class BookView(APIView):
        def get(self, request):
            book_list = Book.objects.all()
            ret = BookSerializer(book_list, many=True)
            return Response(ret.data)
    
        def post(self, request):
            # book_obj = request.data
            print(request.data)
            serializer = BookSerializer(data=request.data)
            if serializer.is_valid():
                print(12341253)
                serializer.save()
                return Response(serializer.validated_data)
            else:
                return Response(serializer.errors)
    
    反序列化views.py

    验证

    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
    
    单个字段的验证
    def my_validate(value):
        if "敏感词汇" in value.lower:
            raise serializers.ValidationError("包含敏感词汇,请重新提交")
        return value
    
    
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(read_only=True)
        title = serializers.CharField(max_length=32, validators=[my_validate])
        # 。。。。。。
        
    
    自定义字段 验证器 validators
        def validate(self, attrs):
            # attrs 是前端传过来的所有的数据组成的字典
            if "python" in attrs["title"] and attrs["post_category"] == 1:
                return attrs
            raise serializers.ValidationError("输入的图书名字或者分类不合法")
    #多个字段
    序列化组件  验证
       单个字段校验  低于自定义权重
          def validate_xxxxx(self, value):
             raise serializers.ValidationError("xxxxx")
             return value
       多个字段  权重最低
          def validate(self, attrs):
             attrs 前端传过来的所有的数据组成的字典
             raise serializers.ValidationError("xxxxx")
             return attrs
       自定义  权重最高
          def my_validate(value):
             raise serializers.ValidationError("xxxxx")
             return value
          title = serializers.CharField(max_length=32, validators=[my_validate, ])

    ModelSerializer

    现在我们已经清楚了Serializer的用法,会发现我们所有的序列化跟我们的模型都紧密相关~

    那么,DRF也给我们提供了跟模型紧密相关的序列化器~~ModelSerializer~~

      -- 它会根据模型自动生成一组字段

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

    定义一个ModelSerializer序列化器

    class BookSerializer(serializers.ModelSerializer):
        category_text = serializers.SerializerMethodField(read_only=True)
        publisher_info = serializers.SerializerMethodField(read_only=True)
        author_info = serializers.SerializerMethodField(read_only=True)
        # 方法字段
        # SerializerMethodField 会去找钩子方法 钩子方法的返回值给这个字段 只用于正序
        # get_字段名称
        # create update 方法自带
    
        def get_category_text(self, obj):
            # obj就是序列化的每个模型对象 book_obj
            return obj.get_category_display()
    
        def get_publisher_info(self, obj):
            return {"id": obj.publisher_id, "title": obj.publisher.title}
    
        def get_author_info(self, obj):
            return [{"id": author.id, "name": author.name} for author in obj.authors.all()]
    
        class Meta:
            model = Book
            fields = "__all__"
            # fields = ["id", "title", "pub_time"]
            # exclude = ["authors"]
            # depth = 1 只跨一张表
            # depth 让你所有的外键关系变成read_only=True,数字显示对应的文字
            # extra_kwargs 给默认字段加额外的参数
            extra_kwargs = {"category": {"write_only": True},
                            "publisher": {"write_only": True},
                            "authors": {"write_only": True}}

    总结:

    
    序列化组件   
       -- 序列化
          -- 声明一个序列化器
             class BookSerializer(serializers.Serializer):
                id = serializers.IntegerField(required=False)
                title = serializers.CharField(max_length=32)
                pub_time = serializers.DateField()
          -- 视图里序列化我们的queryset
             ser_obj = BookSerializer(queryset, many=True)
             return Response(ser_obj.data)
          -- 实现流程
             -- 如果指定了many=True
             -- 把queryset当成可迭代对象去循环 得到每个模型对象
             -- 把每个模型对象放入序列号器进行序列化
             -- 进行字段匹配 匹配上的字段进行序列化 匹配不上丢弃
             -- 必须满足序列化的所有字段要求
       -- 反序列化
          -- 获取前端传过来的数据
          -- 用序列化器进行校验
             ser_obj = BookSerializer(data=request.data)
             if ser_obj.is_valid():
                ser_obj.save()# 调用create方法
                return Response(ser_obj.data)
             else:
                return Response(ser_obj.errors)
          -- 写create方法
             在create方法里用ORM操作创建新对象
       -- 序列化以及反序列化的时候字段类型不统一的情况
          -- required=False 这个字段不需要校验
          -- read_only=True  这个字段正序用
          -- write_only=True 这个字段只反序用
          --partial = True 部分更新
          --"get_category_display"显示对应序号的中文
    
      -- 视图
         ser_obj = BookSerializer(data=request.data)
         if ser_obj.is_valid():
            # 校验通过的数据在ser_obj.validated_data
            ser_obj.save()
            return Response(ser_obj.data)
         return Response(ser_obj.errors)
  • 相关阅读:
    python2.7之打飞机(文末附素材链接)
    python画小猪佩奇
    什么叫递归
    DIV居中的几种方法
    什么是控制反转
    上传图片及时预览
    MVC与三层的区别
    From表单提交刷新页面?
    文件上传之form表单篇
    文件上传之伪Ajax篇
  • 原文地址:https://www.cnblogs.com/yidashi110/p/10102886.html
Copyright © 2011-2022 走看看