zoukankan      html  css  js  c++  java
  • 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)
    
  • 相关阅读:
    numpy 基础 —— np.linalg
    图像旋转后显示不完全
    opencv ---getRotationMatrix2D函数
    PS1--cannot be loaded because the execution of scripts is disabled on this system
    打开jnlp Faild to validate certificate, the application will not be executed.
    BATCH(BAT批处理命令语法)
    oracle vm virtualbox 如何让虚拟机可以上网
    merge 实现
    Windows batch,echo到文件不成功,只打印出ECHO is on.
    python2.7.6 , setuptools pip install, 报错:UnicodeDecodeError:'ascii' codec can't decode byte
  • 原文地址:https://www.cnblogs.com/samoo/p/12117910.html
Copyright © 2011-2022 走看看