字典的update方法
- 可以修改已存在的键对应的值, 也可以添加新的键-值对到字典中
- 语法格式: d.update(e)
- 参数说明: 将e中键-值对添加到字典d中, e可能是字典, 也可能是键-值对序列
- 返回值: 无
- 实例: d = {'one': 1}; d.update({'two': 2}); d.update(one='一'); print(d) #
外键深度查询的方式
- 子序列化
- depth
- @property
接口
'''
# ...\d_proj\api\views.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时的代码执行流程
'''
# ...\Lib\site-packages\rest_framework\serializers.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_proj\api\my_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_proj\api\models.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_proj\api\my_serializers.py
...
class BookModelSerializer(serializers.ModelSerializer):
# ...\d_proj\api\models.py: name = models.CharField(max_length=64, unique=True)
name = serializers.CharField(max_length=64) # 需要自定义name字段的反序列化校验规则, 否则会按照model表中的规则校验unique=True, 导致报错
...
'''