DRF框架(七)——ModelSerializer写接口

目录

ModelSerializer与常规Serializer的不同之处

序列化

反序列化

序列化和反序列化整合(重点)

序列化的四个重要参数


ModelSerializer与常规Serializer的不同之处

  1. 基于模型类自动生成一系列字段
  2. 包含默认的create()和update()的实现
  3. 基于模型类自动为Serializer生成validators,比如unique_together

 

序列化

serializers.py

class BookModelSerializer(ModelSerializer):
    # 自定义连表深度 - 子序列化方式
    publish = PublishModelSerializer()

    class Meta:
        # 序列化类关联的
        model = models.Book
        # 参与序列化的字段
        fields = ('name', 'price', 'author_list', 'publish_name', 'publish')

        # 仅了解
        # 所有字段
        # fields = '__all__'
        # exclude排除字段
        # exclude = ('id', 'is_delete', 'create_time')
        # 自动深度连表
        # depth = 1

model.py中Book类设置publish_name和author_list属性方法

# 自定义字段:可以连表,可以完成数据相关的逻辑
# 序列化插拔式属性 - 完成自定义字段名完成连表查询
    @property
    def publish_name(self):
        return self.publish.name

    @property
    def author_list(self):
        return self.author.values('name', 'age').all()

views.py

class Book(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        # 单查
        if pk:
            try:
                book_obj = models.Book.objects.get(pk=pk, is_delete=False)
                book_data = serializers.BookModelSerializer(book_obj).data
                return Response({
                    'status': 1,
                    'msg': 'ok',
                    'result': book_data
                })
            except:
                return Response({
                    'status': 1,
                    'msg': '书籍不存在'
                })
        # 群查
        else:
            book_query = models.Book.objects.filter(is_delete=False).all()
            book_data = serializers.BookModelSerializer(book_query, many=True).data
            return Response({
                'status': 1,
                'msg': 'ok',
                'result': book_data
            })

应用下路由 urls.py

urlpatterns = [
    url(r'^books/$', views.Book.as_view()),
    url(r'^books/(?P<pk>.*)/$', views.Book.as_view()),
]

 

反序列化

serializers.py

  1. 在设置fields时, 没有默认值的字段都必须设置反序列化保存到数据库中
  2. 使用extra_kwargs来设置系统校验规则
  3. 设置局部钩子和全局钩子
  4. 注意:ModelSerializer类已经帮我们实现了create与update方法,不需要写create就能创建
class BookModelDeserializer(ModelSerializer):
    class Meta:
        model = models.Book
        fields = ('name', 'price', 'authors') #没有默认值的字段必须序列化,为其传值
        # extra_kwargs 用来完成反序列化字段的 系统校验规则
        extra_kwargs = {
            'name': {
                'required': True,
                'min_length': 10,
                'error_message': {
                    'required': '必填项',
                    'min_length': '太短'
                }
            }
        }

    # 局部钩子校验单个字段 validate_字段名
    def validated_name(self, value):
        # 书名不能包含 g 字符
        if 'g' in value.lower():
            raise ValidationError('该g书不能出版')
        return value

    # 全局钩子
    def validate(self, attrs):
        publish = attrs.get('publish') #publish如果是外键字段,这个就是publish对象
        name = attrs.get('name')
        if models.Book.objects.filter(name=name, publish=publish):
            raise ValidationError({'book': '该书已存在'})
        return attrs

 

views.py

  1. POST请求通过request.data拿到数据包
  2. 传给反序列化,通过data=request_data传入需要反序列化的数据
  3. is_valid判断校验是否合格,raise_exception=True必须要写的
  4. 通过.save()保存到数据库中
    def post(self, request, *args, **kwargs):
        request_data = request.data
        book_ser = serializers.BookModelDeserializer(data=request_data)
        # 当校验失败,马上终止当前视图方法,抛异常返回给前台
        book_ser.is_valid(raise_exception=True) #检验是否合格 raise_exception=True必填的
        book_obj = book_ser.save() #保存得到一个对象
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': serializers.BookModelDeserializer(book_obj).data
        })

 

uls.py

  • 在postman中访问路径时最后必须带上/,post请求方式只有json格式能一个字段提交多个值,放在列表或者元祖中,其余两个只能传递单个值
urlpatterns = [
    url(r'^books/$', views.Book.as_view()),
    url(r'^books/(?P<pk>.*)/$', views.Book.as_view()),
]

 

序列化和反序列化整合(重点)

serializers.py

  1. fields中设置所有序列化与反序列化字段
  2. extra_kwargs划分只序列化或只反序列化字段
    • write_only:只反序列化
    • read_only:只序列化
    • 自定义字段默认只序列化(read_only)
    • 如果字段没设置write_only或者read_only,那么该字段可以序列化和反序列化
  3. 设置反序列化所需的 系统、局部钩子、全局钩子等校验规则

 

class V2BookModelSerializer(ModelSerializer):
    class Meta:
        # 序列化类关联的
        model = models.Book
        # 参与序列化的字段
        fields = ('name', 'price', 'img', 'author_list', 'publish_name', 'publish', 'authors')
        extra_kwags = {
            'name': {
                'required': True,
                'min_length': 10,
                'error_message': {
                    'required': '必填项',
                    'min_length': '太短'
                }
            },
            'publish': {
                'write_only': True
            },
            'authors': {
                'write_only': True
            },
            'img': {
                'read_only': True
            },
            'author_list': {
                'read_only': True
            },
            'publish_name': {
                'read_only': True
            },
        }

        # 局部钩子校验单个字段 validate_字段名
        def validated_name(self, value):
            # 书名不能包含 g 字符
            if 'g' in value.lower():
                raise ValidationError('该g书不能出版')
            return value

        # 全局钩子
        def validate(self, attrs):
            publish = attrs.get('publish')  # publish如果是外键字段,这个就是publish对象
            name = attrs.get('name')
            if models.Book.objects.filter(name=name, publish=publish):
                raise ValidationError({'book': '该书已存在'})
            return attrs

views.py

  1. 序列化数据最后必须要.data (因为要传给前端)
  2. 反序列化通过data传参,序列化通过instance传参(当只传一个参数时,默认是instance的参数)
  3. 反序列化与序列化都能使用many=True,序列化和反序列化数据只要被[]嵌套都要写many=True
class V2Book(APIView):
    # 单查:有pk
    # 群查:无pk
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            try:
                book_obj = models.Book.objects.get(pk=pk, is_delete=False)
                book_data = serializers.V2BookModelSerializer(book_obj).data
                return Response({
                    'status': 1,
                    'msg': 'ok',
                    'result': book_data
                })
            except:
                return Response({
                    'status': 1,
                    'msg': '书籍不存在'
                })
        else:
            book_query = models.Book.objects.filter(is_delete=False).all()
            book_data = serializers.V2BookModelSerializer(book_query, many=True).data
            return Response({
                'status': 1,
                'msg': 'ok',
                'result': book_data
            })

    # 单增:传的数据是与model对应的字典
    # 群增:穿的数据是 装多个model对应字典的 列表
    def post(self, request, *args, **kwargs):
        request_data = request.data
        if isinstance(request_data, dict):
            many = False
        elif isinstance(request_data, list):
            many = True
        else:
            return Response({
                'status': 1,
                'msg': '数据有误',
            })
        book_ser = serializers.V2BookModelSerializer(data=request_data, many=many)
        # 当校验失败,马上种植当前视图方法,抛异常返回给前台
        book_ser.is_valid(raise_exception=True) #启动序列化校验规则(系统内容=>局部钩子=>全局钩子)
        book_obj = book_ser.save()
        return Response({
            'status': 0,
            'msg': 'ok',
            'results': serializers.V2BookModelSerializer(book_obj, many=many).data
        })

    # 单删:有pk
    # 群删:有pks
    def delete(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            pks = [pk]
        else:
            pks = request.data.get('pks')
        if models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True):
            return Response({
                'status': 0,
                'msg': '删除成功'
            })
        return Response({
            'status': 1,
            'msg': '删除失败'
        })

urls.py

urlpatterns = [
    url(r'^v2/books/$', views.V2Book.as_view()),
    url(r'^v2/books/(?P<pk>.*)/$', views.V2Book.as_view()),
]

 

序列化的四个重要参数

instance、data、many、partial

序列化情况:

  • 如果没有data参数,只有instance,那么就不存在反序列化校验一说,只有序列化对象instance

反序列化情况:

  • 如果有data,没有instance,那么需要进行校验data,然后将data进行反序列化,得到validated_data后的data,此时再通过序列化对象获取data,这个data和初始化提供的data不一样,这个序列化validated_data后的data,比起初始化data,可能减少了无效的字段(序列化没有定义的字段)

修改情况:

  • 如果又提供了instance又提供了data,那么只要又data或者部分data,那么data都要进行验证才能进行下面的save等操作,如果不经过is_valid过程,那么后面的获取序列化数据或者反序列化数据都会无效。

ListSerializer使用情况:

  • many参数将直接影响序列化类的类型,如果是many=False,那么直接使用当前序列化类。如果many=True,将实例化一个ListSerializer类来序列化或者反序列化类。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值