3.校验,格式化,ModelSerializer使用

【一】反序列化校验

1)三层校验

  • 字段自己校验
    • 直接写在字段类的属性上
  • 局部钩子
    • 在序列化中写validata_字段名
  • 全局钩子
# serializers.py
class BookSerializer(serializers.Serializer):
    # 1) name字段的要大于1小于10
    name = serializers.CharField(min_length=1, max_length=10)
    publish = serializers.CharField()

    # 重建
    def create(self, validated_data):
        book = Book.objects.create(**validated_data)
        return book
    # 2) 局部钩子(针对name字段)
    def validate_name(self, name):
        if "sb" in name:
            raise ValueError('书名中不能有sb')
        else:
            return name
    # 3) 全局钩子
    def validate(self, attrs):
        name = attrs.get('name')
        publish= attrs.get('publish')
        if name == str(publish):
            raise ValidationError('不能相同')
        else:
            return attrs

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from App.models import Book
from App.serializers import BookSerializer


class BookViewSet(APIView):
    # 查询全部
    def get(self, request):
        books = Book.objects.all()
        serializer = BookSerializer(instance=books, many=True)
        return Response(serializer.data)

    # 添加图书
    def post(self, request):
        serializer = BookSerializer(data=request.data)
        ### 若出错,停止代码,直接抛出异常
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response('ok', status=200)

【二】定制返回格式:source

1)定制表中某个字段

  • 直接改名称,并在字段类的属性上添加source='数据库的字段名'
# serializers.py
name = serializers.CharField()
# name改成book_name
book_name = serializers.CharField(source='name')

2)定制模型表

# 将指定字段输出的数据加是'_NB'

# models.py的指定库中
@property
def new_name(self):
    return self.name + '_NB'
# serializers.py
name = serializers.CharField(source='new_name')

3)跨表查询

# 从Book表到publish表
publish= serializers.CharField(source='publish.name')

【三】定制返回格式:序列化

1)一对多关系

1.方式一:使用source

publish= serializers.CharField(source='publish.name')

2.方式二:在模型表中写

# 序列化类中(serializers.py)
# 字典格式用DecimalField,列表用ListField
publish_detail = serializers.DecimalField()

# 指定的模型表内(models.py)
def publish_detail(self):
    return {'name': self.publish.name, 'addr': self.publish.addr}

3.方式三:在序列化类中写

publish = serializers.SerializerMethodField()
    def get_publish(self, obj):
        return {'name': obj.publish.name, 'addr': obj.publish.addr}

4.方式四:使用子序列化

# 在serializers.py内新写函数
class PublishSerializer(serializers.Serializer):
    name = serializers.CharField()
    addr = serializers.CharField()
# 序列化类中写入
publish = PublishSerializer()

2)多对多关系

  • 与一对多相同
# 方式三示例
author = serializers.SerializerMethodField()

def get_author(self, obj):
    authors = obj.author_book.all()
    list_data = []
    for author in authors:
        list_data.append({'name': author.name, 'gender': author.get_gender_display()})
	return list_data

【四】反序列化

  • 通过在序列化类字段内添加参数实现判断
    • read_only=True :只进行序列化操作
    • write_only=True:只进行反序列化操作

1)添加 - 示例

class BookViewSet(APIView):
	def post(self, request):
        serializer = BookSerializer(data=request.data)
        # 若出错,停止代码,直接抛出异常
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response({'code': 200,'message': '添加成功','data': serializer.data})
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from App.models import Book, Author

class BookSerializer(serializers.Serializer):
    name = serializers.CharField(min_length=1, max_length=10)
    publish = serializers.SerializerMethodField(read_only=True)
    def get_publish(self, obj):
        return {'name': obj.publish.name, 'addr': obj.publish.addr}

    author = serializers.SerializerMethodField(read_only=True)
    def get_author(self, obj):
        authors = obj.author_book.all()
        list_data = []
        for author in authors:
            list_data.append({'name': author.name, 'gender': author.get_gender_display()})
        return list_data

    publish_id= serializers.IntegerField(write_only=True)
    author_id = serializers.ListField(write_only=True)

    # 重建create
    def create(self, validated_data):
        # 弹出author_id
        author = validated_data.pop('author_id')
        book = Book.objects.create(**validated_data)
        book.author_book.add(*author)
        return book

2)修改 - 示例

class BookDetailViewSet(APIView):
    ...
    # 改
    def put(self, request, pk):
        book = Book.objects.get(pk=pk)
        serializer = BookSerializer(instance=book, data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response({'code': 200,'message': '添加成功','data': serializer.data})
# serializers.py内
class BookSerializer(serializers.Serializer):
    ...
    # 重建update(旧,新)
    def update(self, instance, validated_data):
        # 弹出作者
        author = validated_data.pop('author_id')
        # 清除关系在添加
        instance.author_book.clear()
        instance.author_book.add(*author)
        # 修改Book表
        for key in validated_data:
            setattr(instance, key, validated_data.get(key))
        instance.save()
        return instance

【五】ModelSerializer的使用

1)介绍

  • ModelSerializer与模型表一一对应
  • 可用不重写 create 和 update 便能进行添加修改
  • 序列化与反序列化字段,可通过表映射

2)使用-示例

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        # 获取Book数据库中所有字段
        # 包括关联的表(publish,author_book)
        fields = '__all__'
        # 获取指定字段
        # fields = ['name', 'publish']
        # 校验书写
        extra_kwargs = {
            'name': {'min_length': 1,'max_length': 10},
            'publish': {'writer_only': True},
            'author_book': {'writer_only': True},
        }

        # 局部钩子
        def validate_name(self, name):
            ...
            return name

        # 全局钩子
        def validate(self, attrs):
            ...
            return attrs

3)定制返回格式-示例

class BookModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        # 获取指定字段
        # 新增的需要注册才能使用
        fields = ['name', 'publish_data','author_book_data']
        # 校验书写
        extra_kwargs = {
            'name': {'min_length': 1, 'max_length': 10},
            'publish_data': {'read_only': True},
            'author_book_data': {'read_only': True},
        }

    publish_data = serializers.SerializerMethodField()
    def get_publish_data(self, obj):
        return {'name': obj.publish.name, 'addr': obj.publish.addr}

    author_book_data = serializers.SerializerMethodField(read_only=True)
    def get_author_book_data(self, obj):
        authors = obj.author_book.all()
        list_data = []
        for author in authors:
            list_data.append({'name': author.name, 'gender': author.get_gender_display()})
        return list_data
posted on 2024-08-01 10:39  晓雾-Mist  阅读(3)  评论(0编辑  收藏  举报