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 区别

 

posted @ 2020-09-15 10:33  亦双弓  阅读(140)  评论(0编辑  收藏  举报