zoukankan      html  css  js  c++  java
  • 字典的update方法, 外键深度查询的方式

    字典的update方法

    • 可以修改已存在的键对应的值, 也可以添加新的键-值对到字典中
    • 语法格式: d.update(e)
    • 参数说明: 将e中键-值对添加到字典d中, e可能是字典, 也可能是键-值对序列
    • 返回值: 无
    • 实例: d = {'one': 1}; d.update({'two': 2}); d.update(one='一'); print(d) # {'one': '一', 'two': 2}

    外键深度查询的方式

    1. 子序列化
    2. depth
    3. @property

    接口

    '''
    # ...d_projapiviews.py
    ...
    class BookAPIView(APIView):
        ...
        # 单删群删, 将需要被删除的数据的is_delete字段值修改为True 
        """
        1. 单删接口: .../books/(pk)/
        2. 群删接口: .../books/, 携带数据: [pk1, ..., pkn]
        """
        def delete(self, request, *args, **kwargs):
        	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 Response(data={
        			'code': 1,	
                    'res': {'detail': '数据有误'},
        		}, status=400)
        	
        	if rows:
        		return Response(data={
        			'code': 0,	
                    'res': '删除成功',
        		}, status=200) 
        
        # 单增群增
        def post(self, request, *args, **kwargs):
            """
            1. 单增接口: .../books/, 携带数据: {...}
            2. 群增接口: .../books/, 携带数据: [{...}, ..., {...}]
            """
            try:
                if not request.data:
                    raise Exception('数据不能为空')
                if isinstance(request.data, dict):
                    many = False
                else:
                    many = True
                book_ser = serializers.BookModelSerializer(data=request.data, many=many)
            except Exception as e:
                return Response(data={
                    'code': 1,
                    'res': {'detail': str(e)},
                }, status=400)
    
            book_ser.is_valid(raise_exception=True)
            res_book_obj_or_lt = book_ser.save()
            re_book_ser = serializers.BookModelSerializer(instance=res_book_obj_or_lt, many=many)
            return Response(data={
                'code': 0,
                'res': re_book_ser.data,
            }, status=200)
        		
    	# 单改群改所有字段: 没有提供修改值的字段沿用原字段值而不是默认值
        def put(self, request, *args, **kwargs):
            """
            1. 单改所有字段接口: .../books/, 携带数据: {pk: ..., ...}
            2. 群改所有字段接口: .../books/, 携带数据: [{pk1: ..., ...}, ..., {pkn: ..., ...}]
            """
    
            if isinstance(request.data, dict):
                request.data = [request.data]  # 将单改统一成群改的形式
    
            # 群改所有字段时如果有一条被修改的数据出错, 则直接认为put请求提交的整个数据都有误
            try:
                pks = []
                for dic in request.data:
                    pk = dic.pop('pk')  # 字典的pop方法不设置默认值时, 如果被pop的数据在字典中不存在则会直接报错
                    pks.append(pk)
                book_queryset = models.Book.objects.filter(is_delete=False, pk__in=pks).all()
                if len(book_queryset) < len(pks):
                    raise Exception('部分要修改的数据不存在')
    
            except Exception as e:
                if isinstance(e, KeyError):
                    e = '部分数据缺少pk'
                return Response(data={
                    'code': 1,
                    'res': {'detail': str(e)},  # e为异常对象, 需要转换成字符串才能返回给前端
                }, status=400)
    
            book_ser = serializers.BookModelSerializer(instance=book_queryset, data=request.data, many=True)
    
            book_ser.is_valid(raise_exception=True)
            res_book_queryset = book_ser.save()  # drf框架不实现群改方法的原因: 需要对queryset和request.data提前作一些不可控的处理
            re_book_ser = serializers.BookModelSerializer(instance=res_book_queryset, many=True)
            return Response(data={
                'code': 0,
                'res': re_book_ser.data,
            }, status=200)
    
    	# 单改群该部分字段: 改部分字段兼容改所有字段, 之后只需要写patch方法并在BookModelSerializer类实例化时添加partial=True即可
    	def patch(self, request, *args, **kwargs):
    		...
    		# 通过context在BookAPIView类的方法中给序列化类传参, 在序列化类的方法中可以通过self.context获取从自定义的CBV类中传入的变量
    		book_ser = serializers.BookModelSerializer(..., partial=True, context={'request': request})    		
    '''
    

    Debug打断点研究many=True时的代码执行流程

    '''   
    # ...Libsite-packages
    est_frameworkserializers.py
    class BaseSerializer(Field):
    	    def __init__(self, instance=None, data=empty, **kwargs):  # ModelSerializer类中没有__init__方法
            self.instance = instance
            ...
            kwargs.pop('many', None)
            super().__init__(**kwargs)
            
        def __new__(cls, *args, **kwargs):
            if kwargs.pop('many', False):
                return cls.many_init(*args, **kwargs)  # cls为BookModelSerializer类
            return super().__new__(cls, *args, **kwargs)
            
        @classmethod
        def many_init(cls, *args, **kwargs):
            ...
            child_serializer = cls(*args, **kwargs)
            list_kwargs = {
                'child': child_serializer,  # child为BookModelSerializer类的对象
            }
            ...
            meta = getattr(cls, 'Meta', None)
            list_serializer_class = getattr(meta, 'list_serializer_class', ListSerializer)  
            return list_serializer_class(*args, **list_kwargs)  # 当many=True时, 返回list_serializer_class配置的类的对象
    
    
    class ListSerializer(BaseSerializer):
        ...
        def __init__(self, *args, **kwargs):  # self为list_serializer_class配置的类的对象
            self.child = kwargs.pop('child', copy.deepcopy(self.child))  # child为BookModelSerializer类的对象child属性
            ...
            
    	...    
        def update(self, instance, validated_data):  # 群改方法需要仿照群增方法自己实现
            raise NotImplementedError(
                ...
            )
    
        def create(self, validated_data):
            return [
                self.child.create(attrs) for attrs in validated_data
            ]
            
        def save(self, **kwargs):
            ...
            if self.instance is not None:
                self.instance = self.update(self.instance, validated_data)
                ...
            else:
                self.instance = self.create(validated_data)
                ...
            return self.instance
            
            
    # ...d_projapimy_serializers.py
    ...
    class BookListSerializer(serializers.ListSerializer):
        def update(self, instance, validated_data):
            return [
                self.child.update(instance[index], attrs) for index, attrs in enumerate(validated_data)
            ]
    
    
    class BookModelSerializer(serializers.ModelSerializer):
    	# ...d_projapimodels.py: name = models.CharField(max_length=64, unique=True)
    	name = serializers.CharField(max_length=64)  # 需要自定义name字段的反序列化校验规则, 否则会按照model表中的规则校验unique=True, 导致报错
    	
        class Meta:
            list_serializer_class = BookListSerializer
            ...
    '''
    

    一个花了很多时间的bug

    '''
    # ...d_projapimy_serializers.py
    ...
    class BookModelSerializer(serializers.ModelSerializer):
    	# ...d_projapimodels.py: name = models.CharField(max_length=64, unique=True)
    	name = serializers.CharField(max_length=64)  # 需要自定义name字段的反序列化校验规则, 否则会按照model表中的规则校验unique=True, 导致报错
        ...
    '''
    
  • 相关阅读:
    ASP.NET MVC基于标注特性的Model验证:DataAnnotationsModelValidator
    TDD个人实践体会
    客户端调用Spring.Net发布的WebService
    XML自动解析器开源
    Javascript MVVM模式前端框架—Knockout 2.1.0系列
    定时执行SQL存储过程
    orchard之lucene.net索引生成
    并发编程学习总结
    python开发总结
    Thrift
  • 原文地址:https://www.cnblogs.com/-406454833/p/12708770.html
Copyright © 2011-2022 走看看