• Day 88 Django_DRF 序列化


    DRF 序列化

    官方文档:https://www.django-rest-framework.org

    第一步:

    pip清华源安装djangorestframework :

    pip install -i https://pypi.tuna.tsinghua.edu.cn/simple djangorestframework

    查看 pip 中已经安装的包:pip list | findstr "djangorestframework" 

     

    第二步:

    配置 settings.py

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'APP.apps.AppConfig',
        'rest_framework'       # 添加该行
    ]

    第三步:

    新建文件,编写序列化类

    serializers.py

    # -*- coding: utf-8 -*-
    
    # @File    : serializers.py
    # @Date    : 2020-09-14
    # @Author  : Administrator
    
    from rest_framework import serializers
    
    class PublisherSerializers(serializers.Serializer):
        id = serializers.IntegerField()
        title = serializers.CharField(max_length=32)
    
    class AuthorSerializers(serializers.Serializer):
        id = serializers.IntegerField()
        Author_name = serializers.CharField(max_length=32)
    
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField()
        title = serializers.CharField(max_length=32)
        CHOICES = ((1, 'Java'), (2, 'MySQL'), (3, 'Python'),)
        category = serializers.ChoiceField(choices=CHOICES,source='get_category_display') # 显示 CHOICES 中的中文 需设置 source
        pub_time = serializers.DateField()
    
        # 关联外键
        publisher = PublisherSerializers()
        author = AuthorSerializers(many=True)   # 告诉 serializers 这是一个 ManyToManyField
    View Code

    重新编写 views 类,注意继承类,要使用 serializers 中的相关数据

    views.py

    from .models import Book
    
    from .serializers import BookSerializer
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    class BookView(APIView):    # 继承 APIView
        def get(self,request):
            # book_obj = Book.objects.first()
            # ret = BookSerializer(book_obj)
            book_list = Book.objects.all()
            ret = BookSerializer(book_list,many=True)   # 多条数据时,一定要告诉 BookSerializer 序列化多条数据
            return Response(ret.data)
    View Code

    DRF 反序列化

    serializers.py

    # -*- coding: utf-8 -*-
    
    # @File    : serializers.py
    # @Date    : 2020-09-14
    # @Author  : Administrator
    
    from rest_framework import serializers
    from .models import Book
    
    
    class PublisherSerializers(serializers.Serializer):
        id = serializers.IntegerField()
        title = serializers.CharField(max_length=32)
    
    
    class AuthorSerializers(serializers.Serializer):
        id = serializers.IntegerField()
        Author_name = serializers.CharField(max_length=32)
    
    
    # {
    #         "title": "java入门",
    #         "w_category": 1,
    #         "pub_time": "2020-09-14",
    #         "w_publisher_id": 1,
    #         "w_author_list": [1,2]
    #     }
    
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)
        title = serializers.CharField(max_length=32)
        CHOICES = ((1, 'Java'), (2, 'MySQL'), (3, 'Python'),)
        category = serializers.ChoiceField(choices=CHOICES, source='get_category_display', read_only=True)  # 序列化的时候读
        w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
        pub_time = serializers.DateField()
    
        w_publisher_id = serializers.IntegerField(write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
        w_author_list = serializers.ListField(write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
    
        # 关联外键
        publisher = PublisherSerializers(read_only=True)
        author = AuthorSerializers(many=True, read_only=True)  # 告诉 serializers 这是一个 ManyToManyField
    
        def create(self, validated_data):
            book = Book.objects.create(title=validated_data['title'], category=validated_data['w_category'],
                                pub_time=validated_data['pub_time'],publisher_id=validated_data['w_publisher_id'])
    
            book.author.add(*validated_data['w_author_list'])   # 多对多进行解包
            return book
    serializers.py

    views.py

    from .models import Book, Publisher
    from .serializers import BookSerializer
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    
    # 第三版 DRF 序列化
    class BookView(APIView):  # 继承 APIView
        def get(self, request):
            # book_obj = Book.objects.first()
            # ret = BookSerializer(book_obj)
            book_list = Book.objects.all()
            ret = BookSerializer(book_list, many=True)  # 多条数据时,一定要告诉 BookSerializer 序列化多条数据
            return Response(ret.data)
    
        # Post 请求,反序列化
        def post(self, request):
            print(request.data)
            serializers = BookSerializer(data=request.data)
            if serializers.is_valid():
                serializers.save()
                return  Response(serializers.validated_data)
            else:
                return Response(serializers.errors)
    View Code

    DRF 获取指定单条数据

    urls.py

    from django.urls import path,include
    from .views import BookView,BookEditView
    
    urlpatterns = [
        path('EditBook/<int:id>',BookEditView.as_view())
    ]

    view.py

    class BookEditView(APIView):
        def get(self,request,id):
            book = Book.objects.filter(id=id).first()
            ret = BookSerializer(book)
            return Response(ret.data)

    DRF 的 PUT 请求部分验证

    serializers.py

    # -*- coding: utf-8 -*-
    
    # @File    : serializers.py
    # @Date    : 2020-09-14
    # @Author  : Administrator
    
    from rest_framework import serializers
    from .models import Book
    
    
    class PublisherSerializers(serializers.Serializer):
        id = serializers.IntegerField()
        title = serializers.CharField(max_length=32)
    
    
    class AuthorSerializers(serializers.Serializer):
        id = serializers.IntegerField()
        Author_name = serializers.CharField(max_length=32)
    
    
    # {
    #         "title": "java入门",
    #         "w_category": 1,
    #         "pub_time": "2020-09-14",
    #         "w_publisher_id": 1,
    #         "w_author_list": [1,2]
    #     }
    
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)
        title = serializers.CharField(max_length=32)
        CHOICES = ((1, 'Java'), (2, 'MySQL'), (3, 'Python'),)
        category = serializers.ChoiceField(choices=CHOICES, source='get_category_display', read_only=True)  # 序列化的时候读
        w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
        pub_time = serializers.DateField()
    
        w_publisher_id = serializers.IntegerField(write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
        w_author_list = serializers.ListField(write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
    
        # 关联外键
        publisher = PublisherSerializers(read_only=True)
        author = AuthorSerializers(many=True, read_only=True)  # 告诉 serializers 这是一个 ManyToManyField
    
        def create(self, validated_data):
            book = Book.objects.create(title=validated_data['title'], category=validated_data['w_category'],
                                pub_time=validated_data['pub_time'],publisher_id=validated_data['w_publisher_id'])
    
            book.author.add(*validated_data['w_author_list'])   # 多对多进行解包
            return book
    
        def update(self, instance, validated_data):
            instance.title = validated_data.get('title',instance.title)
            instance.category = validated_data.get('category',instance.category)
            instance.pub_time = validated_data.get('pub_time',instance.pub_time)
            instance.publisher_id = validated_data.get('publisher_id',instance.publisher_id)
    
            if validated_data.get('w_author_list'):
                instance.author.set(validated_data['w_author_list'])
            instance.save()
            return instance
    serializers.py

    views.py

    class BookEditView(APIView):
        def get(self,request,id):
            book_obj = Book.objects.filter(id=id).first()
            ret = BookSerializer(book_obj)
            return Response(ret.data)
    
        def put(self,request,id):
            book_obj = Book.objects.filter(id=id).first()
            ret = BookSerializer(book_obj,data=request.data,partial=True)   # partial 是否允许部分更新
            if ret.is_valid():
                ret.save()
                return Response(ret.validated_data)
            else:
                return Response(ret.errors)
    View.py

     

    DRF的钩子验证

    优先级:局部钩子  >  自定义钩子  >  全局钩子

    局部钩子验证

    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)
        title = serializers.CharField(max_length=32)
        CHOICES = ((1, 'Java'), (2, 'MySQL'), (3, 'Python'),)
        category = serializers.ChoiceField(choices=CHOICES, source='get_category_display', read_only=True)  # 序列化的时候读
        w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
        pub_time = serializers.DateField()
    
        w_publisher_id = serializers.IntegerField(write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
        w_author_list = serializers.ListField(write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
    
        # 关联外键
        publisher = PublisherSerializers(read_only=True)
        author = AuthorSerializers(many=True, read_only=True)  # 告诉 serializers 这是一个 ManyToManyField
    
        def create(self, validated_data):
            book = Book.objects.create(title=validated_data['title'], category=validated_data['w_category'],
                                pub_time=validated_data['pub_time'],publisher_id=validated_data['w_publisher_id'])
    
            book.author.add(*validated_data['w_author_list'])   # 多对多进行解包
            return book
    
        def update(self, instance, validated_data):
            instance.title = validated_data.get('title',instance.title)
            instance.category = validated_data.get('category',instance.category)
            instance.pub_time = validated_data.get('pub_time',instance.pub_time)
            instance.publisher_id = validated_data.get('publisher_id',instance.publisher_id)
    
            if validated_data.get('w_author_list'):
                instance.author.set(validated_data['w_author_list'])
            instance.save()
            return instance
    
        # 局部钩子,定义 title 的局部验证
        def validate_title(self, vaule):
            if 'Python' not in vaule:
                raise serializers.ValidationError('标题必须含有 Python')
            return vaule
    局部钩子

    全局钩子验证

    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)
        title = serializers.CharField(max_length=32)
        CHOICES = ((1, 'Java'), (2, 'MySQL'), (3, 'Python'),)
        category = serializers.ChoiceField(choices=CHOICES, source='get_category_display', read_only=True)  # 序列化的时候读
        w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
        pub_time = serializers.DateField()
    
        w_publisher_id = serializers.IntegerField(write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
        w_author_list = serializers.ListField(write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
    
        # 关联外键
        publisher = PublisherSerializers(read_only=True)
        author = AuthorSerializers(many=True, read_only=True)  # 告诉 serializers 这是一个 ManyToManyField
    
        def create(self, validated_data):
            book = Book.objects.create(title=validated_data['title'], category=validated_data['w_category'],
                                pub_time=validated_data['pub_time'],publisher_id=validated_data['w_publisher_id'])
    
            book.author.add(*validated_data['w_author_list'])   # 多对多进行解包
            return book
    
        def update(self, instance, validated_data):
            instance.title = validated_data.get('title',instance.title)
            instance.category = validated_data.get('category',instance.category)
            instance.pub_time = validated_data.get('pub_time',instance.pub_time)
            instance.publisher_id = validated_data.get('publisher_id',instance.publisher_id)
    
            if validated_data.get('w_author_list'):
                instance.author.set(validated_data['w_author_list'])
            instance.save()
            return instance
    
        # 局部钩子,定义 title 的局部验证
        def validate_title(self, vaule):
            if 'Python' not in vaule:
                raise serializers.ValidationError('标题必须含有 Python')
            return vaule
    
        # 全局钩子
        def validate(self, attrs):
            if attrs['w_publisher_id'] !=2 or attrs['w_category'] != 2:
            # if 2 not in attrs['w_author_list']:
                raise serializers.ValidationError('出版社或作者不正确')
            return attrs
    全局钩子

    自定义钩子验证

    def my_validate(attrs):
        if "敏感信息" in attrs.lower():
            raise serializers.ValidationError('含有了敏感信息')
        return attrs
    
    class BookSerializer(serializers.Serializer):
        id = serializers.IntegerField(required=False)
        title = serializers.CharField(max_length=32,validators=[my_validate])
        CHOICES = ((1, 'Java'), (2, 'MySQL'), (3, 'Python'),)
        category = serializers.ChoiceField(choices=CHOICES, source='get_category_display', read_only=True)  # 序列化的时候读
        w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
        pub_time = serializers.DateField()
    
        w_publisher_id = serializers.IntegerField(write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
        w_author_list = serializers.ListField(write_only=True)  # 该字段用于反序列化,且只作用于反序列化时
    
        # 关联外键
        publisher = PublisherSerializers(read_only=True)
        author = AuthorSerializers(many=True, read_only=True)  # 告诉 serializers 这是一个 ManyToManyField
    自定义钩子

    ModelSerializer序列化

    serializers.py

    from rest_framework import serializers
    from .models import Book
    
    
    class BookSerializer(serializers.ModelSerializer):
        category = serializers.CharField(source='get_category_display')
        publisher = serializers.SerializerMethodField()
        author = serializers.SerializerMethodField()
    
        # 通过自定义 get_publisher 与 get_author 来获取我们想要的指定字段
        def get_publisher(self,obj):
            # obj 是我们序列化的每个 Book 对象
            publisher_obj = obj.publisher
            return {"id":publisher_obj.id,"title":publisher_obj.title}
    
        def get_author(self,obj):
            author_obj = obj.author.all()
            print(obj.author.all())
            return [{'id':author.id,'Author_name':author.Author_name} for author in author_obj]
    
        class Meta:
            model = Book
            # fields = ['id','title','pub_time']  # 拿到指定信息
            fields = '__all__'      # 拿到所有信息,但存在关联字段 id 信息,不利于阅读,需要单独处理
            # depth = 1   # 获取关联表中的字段,数字代表 深度,但这样回取出所有数据
    serializers.py

    ModelSerializer反序列化

    ModelSerializer 已经默认给我们写了 create 方法

    serializers.py

    from rest_framework import serializers
    from .models import Book
    
    class BookSerializer(serializers.ModelSerializer):
        category = serializers.SerializerMethodField(read_only=True)
        publisher_info = serializers.SerializerMethodField(read_only=True)
        authors = serializers.SerializerMethodField(read_only=True)
    
        def get_category(self, obj):
            return obj.get_category_display()
    
        # 通过自定义 get_publisher 与 get_author 来获取我们想要的指定字段
        def get_publisher_info(self, obj):
            # obj 是我们序列化的每个 Book 对象
            publisher_obj = obj.publisher
            return {"id": publisher_obj.id, "title": publisher_obj.title}
    
        def get_authors(self, obj):
            author_obj = obj.author.all()
            print(obj.author.all())
            return [{'id': author.id, 'Author_name': author.Author_name} for author in author_obj]
    
        class Meta:
            model = Book
            # fields = ['id','title','pub_time']  # 拿到指定信息
            fields = '__all__'  # 拿到所有信息,但存在关联字段 id 信息,不利于阅读,需要单独处理
            # depth = 1   # 获取关联表中的字段,数字代表 深度,但这样回取出所有数据
    
            # extra_kwargs 添加字段的属性信息
            extra_kwargs = {"category": {"write_only": True}, "publisher": {"write_only": True},
                            "author": {"write_only": True}}
    serializers.py

    Serializer 以及 ModelSerializer 区别

  • 相关阅读:
    Vue响应式原理
    vue 与 react
    vuex
    受控组件( controlled component )与不受控制的组件( uncontrolled component )区别
    redux学习语录
    Flux
    MVC和MVVM 架构模式/设计思想
    immutable
    JS中一些兼容性问题
    @芥末的糖 ---------- node连接数据库两种方式mysql和moogoDB
  • 原文地址:https://www.cnblogs.com/ysging/p/13667550.html
Copyright © 2020-2023  润新知