• rest-framework(五)


    子序列化

    class PublishModelSerializer(serializers.ModelSerializer):
        # books = BookModelSerializer(many=True)
        class Meta:
            model = models.Publish
            fields = ['name', 'address', 'books']
    
            # fields = '__all__'
            # exclude = ['name']
            # depth = 2  # 自动深度,值代表深度次数,但是被深度的外键采用__all__,显示所以字段
    

    Response二次封装

    #View
    class BookAPIView(APIView):
        def get(self, request, *args, **kwargs):
            book_query = models.Book.objects.all()
            book_ser = serializers.BookModelSerializer(book_query, many=True)
            # return Response(
            #     data={
            #     'status': 0,
            #     'msg': 'ok',
            #     'results': book_ser.data
            #     },
            #     status=200,
            #     exception=False
            # )
            return APIResponse(result=book_ser.data)
    #--------------------------------------------------------
    #自定义response
    class APIResponse(Response):
        def __init__(self,status=0,msg='ok',results=None,http_status=None,
                     exception=None,headers=None,content_type=None,**kwargs):
            data = {
                'status':status,
                'msg':msg,
            }
            if results is not None:
                data['results'] = results
    
            #将kwargs中额外的k-v数据添加到data中
            data.update(**kwargs)
            super().__init__(data=data,status=http_status,headers=headers,exception=exception,content_type=content_type)
    

    连表深度查询

    '''
    外键字段默认显示的是外键值(int),不会自己进行深度查询
      深度查询方式:
        1.子序列化:必须有子序列化类配合,不能反序列化
        
        2.配置depth:自动深度查询的是关联表的所有字段,数据量太多
        
        3.插拔式@property:名字不能与外键名同名
    '''
    #----------------------------------------------------
    #在model中定义装饰@property字段,使用插拔式
    class Book(BaseModel):
        name = models.CharField(max_length=64)
        price = models.DecimalField(max_digits=10, decimal_places=2)
        publish = models.ForeignKey(to='Publish', related_name='books', db_constraint=False, on_delete=models.DO_NOTHING, null=True)
        authors = models.ManyToManyField(to='Author', related_name='books', db_constraint=False)
    
        @property
        def publish_info(self):
            return {
                'name':self.publish.name,
                'address':self.publish.address,
            }
    #-------------------------------------------------------
    #在serializers中插入字段
    class BookModelSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = ['name','price','publish','authors','publish_info']
    
    
    #显示书籍作者的详情
    @property
        def author_list(self):
            author_list_temp = []  # 存放所有作者格式化成数据的列表
            authors = self.authors.all()  # 所有作者
            for author in authors:  # 遍历处理所有作者
                author_dic = {
                    'name': author.name,
                }
                try:  # 有详情才处理详情信息
                    author_dic['mobile'] = author.detail.mobile
                except:
                    author_dic['mobile'] = '无'
    
                author_list_temp.append(author_dic)  # 将处理过的数据添加到数据列表中
    
            return author_list_temp  # 返回处理后的结果
    

    单删群删接口

    # 单删群删
    def delete(self, request, *args, **kwargs):
        '''
        单删:/books/(pk)/
    
        群删:/books/          数据:[pk1,....pkn]
        逻辑:修改is_delete字段,修改成功代表删除成功,修改失败代表删除失败
        '''
        pk = kwargs.get('pk')
        if pk :
            # 将单删格式化成一条
            pks = [pk]
        else:
            # 该出要做数据处理
            pks = request.data
        try:
            rows = models.Book.objects.filter(is_delete=False,pk__in=pks).update(is_delete=True)
        except :
            return APIResponse(1,'数据有误')
        if rows:
            return APIResponse(0,'删除成功')
        return APIResponse(0,'删除成功')
    

    单增群增接口

    def post(self, request, *args, **kwargs):
        '''
        单增:/books/      数据"{}
        全增:/books/      数据:[{}]
        逻辑:将数据给序列化类处理,数据的类型关系到many属性是否为True
        '''
        if isinstance(request.data,dict):
            many = False
        elif isinstance(request.data,list):
            many = True
        else:
            return Response(data={'detail':'数据错误'},status=404)
        book_ser = serializers.BookModelSerializer(data=request.data,many=many)
        book_ser.is_valid(raise_exception=True)
        book_obj_or_list = book_ser.save()
        return APIResponse(results=serializers.BookModelSerializer(book_obj_or_list,many=many).data)
    

    单改群改接口

        # 整体单改群改
        def put(self, request, *args, **kwargs):
            """
            单改:接口:/books/(pk)/   数据:{...}
            群增:接口:/books/   数据:[{pk, ...}, ..., {pk, ...}]
            逻辑:将数据给系列化类处理,数据的类型关系到 many 属性是否为True
            """
            pk = kwargs.get('pk')
            if pk:  # 单改
                try:
                    # 与增的区别在于,需要明确被修改的对象,交给序列化类
                    book_instance = models.Book.objects.get(is_delete=False, pk=pk)
                except:
                    return Response({'detail': 'pk error'}, status=400)
    
                book_ser = serializers.BookModelSerializer(instance=book_instance, data=request.data)
                book_ser.is_valid(raise_exception=True)
                book_obj = book_ser.save()
                return APIResponse(results=serializers.BookModelSerializer(book_obj).data)
            else:  # 群改
                # 分析(重点):
                # 1)数据是列表套字典,每个字典必须带pk,就是指定要修改的对象,如果有一条没带pk,整个数据有误
                # 2)如果pk对应的对象已被删除,或是对应的对象不存在,可以认为整个数据有误(建议),可以认为将这些错误数据抛出即可
                request_data = request.data
                try:
                    pks = []
                    for dic in request_data:
                        pk = dic.pop('pk')  # 解决分析1,没有pk pop方法就会抛异常
                        pks.append(pk)
    
                    book_query = models.Book.objects.filter(is_delete=False, pk__in=pks).all()
                    if len(pks) != len(book_query):
                        raise Exception('pk对应的数据不存在')
                except Exception as e:
                    return Response({'detail': '%s' % e}, status=400)
    
                book_ser = serializers.BookModelSerializer(instance=book_query, data=request_data, many=True)
                book_ser.is_valid(raise_exception=True)
                book_list = book_ser.save()
                return APIResponse(results=serializers.BookModelSerializer(book_list, many=True).data)
    

    群改

    #如果只有群增是不需要自定义配置的,但是验完成群改,必须自定义配置
    # 单改整改
    def put(self,request,*args, **kwargs):
        '''
        单改: /books/(pk)/    数据:{...}
        群改: /books/   数据:[{pk...}]
        逻辑: 将数据给序列化类处理,数据的类型关系到many属性是否为True
        '''
        pk = kwargs.get('pk')
        # 单改
        if pk:
            try:
                book_instance = models.Book.objects.get(is_delete=False, pk=pk)
            except:
                return Response({'detail':'pk error'},status=400)
            book_ser = serializers.BookModelSerializer(instance=book_instance, data=request.data)
            book_ser.is_valid(raise_exception=True)
            book_obj = book_ser.save()
            return APIResponse(results=serializers.BookModelSerializer(book_obj).data)
    #-------------------------------------------------------
    #在serializer文件自定义群改方法
    class BookListSerializer(serializers.ListSerializer):
        # ListSerializer没有自带封装群改方法,需要自己重写
        def update(self, instance_list, validated_data):
            # for index,attrs in enumerate(validated_data):
            return [
                self.child.update(instance_list[index],attrs) for index,attrs in enumerate(validated_data)
            ]
        
    #在Mate中设置使用自己定义的update方法
    class BookModelSerializer(serializers.ModelSerializer):
        # 外键字段默认显示的是外键值(int),不会自己进行深度查询
        # 深度查询方式:
        # 1.子序列化:必须有子序列化类配合,不能反序列化
        # 2.配置depth:自动深度查询的是关联表的所有字段,数据量太多
        # 3.插拔式@property:名字不能与外键名同名
        class Meta:
            #如果只有群增是不需要自定义配置的,但是验完成群改,必须自定义配置
            list_serializer_class = BookListSerializer
            model = models.Book
            fields = ['name','price','publish','authors','publish_info','author_list']
            extra_kwargs = {
                'publish':{
                    'write_only':True
                },
                'authors':{
                    'write_only': True
                }
            }
    #-------------------------------------------------------
        # 群改
        else:
            # 群改分析:
            # 1. 每个数据是列表套字典,每个字典必须带pk,就是指定要修改的对象,如果有一条数据没带pk,整个数据有误
            # 2. 如果pk对应的对象已被删除,或是对应的对象不存在,可以认为整个数据有误,可以将这些错误数据抛出即可
            request_data = request.data
            try:
                pks = []
                for dic in request_data:
                    # 解决分析1,没有pk,,pop方法就会抛异常
                    pk = dic.pop('pk')
                    pks.append(pk)
                book_query = models.Book.objects.filter(is_delete=False,pk__in=pks).all()
    
                if len(pks) != len(request_data):
                    raise Exception('pk错误')
            except Exception as e:
                return Response({'detail':'%s'%e},status=400)
    
            book_ser = serializers.BookModelSerializer(many=True,instance=book_query, data=request.data)
            book_ser.is_valid(raise_exception=True)
            book_obj = book_ser.save()
            return APIResponse(results=serializers.BookModelSerializer(book_obj).data)
    

    局部改

    设置partial=True,将所有字段设置为可选改,其余和全局单改群改一样

    '''
    # 设置partial=True的序列化类,参与反序列化的字段,都会置为选填字段
                # 1)提供了值得字段发生修改。
                # 2)没有提供的字段采用被修改对象原来的值
    
                # 设置context的值,目的:在序列化完成自定义校验(局部与全局钩子)时,可能需要视图类中的变量,如请求对象request
                # 可以通过context将其传入,在序列化校验方法中,self.context就能拿到传入的视图类中的变量
    
    '''
    	book_ser = serializers.BookModelSerializer(many=True,instance=book_query, data=request.data,partial=True)
    
  • 相关阅读:
    底层原理
    No.1
    No.3
    No.0
    php 10进制转62进制,可用于短网址生成
    php实现斐波那契数列
    五种常见的 PHP 设计模式
    PHP利用MySQL保存session
    HTTP相关
    如何优化tomcat配置(从内存、并发、缓存4个方面)优化
  • 原文地址:https://www.cnblogs.com/samoo/p/12117910.html
Copyright © 2020-2023  润新知