Django REST Framework序列化器验证报错:如何避免重复查询Category
解决Django REST Framework序列化器中避免重复查询数据库的问题
首先,你遇到的错误核心原因是:在validate方法中直接修改或访问self.data是不允许的——self.data是序列化器完成验证和序列化流程后生成的只读属性,在is_valid()执行过程中操作它就会触发这个报错。
最优解决方案:将Category实例存储到序列化器自定义属性
不要把查询到的Category实例放到self.data里,而是存到序列化器实例的一个自定义属性(比如self.category)中,这样在视图里就能直接获取,完全避免第二次数据库查询。
修改你的SearchSerializer代码如下:
class SearchSerializer(serializers.Serializer): category_id = serializers.IntegerField() search_term = serializers.CharField(required=False) def validate(self, data): try: # 查询Category实例并存储到序列化器自定义属性 self.category = Category.objects.get(pk=data['category_id']) except Category.DoesNotExist: raise serializers.ValidationError('Invalid category_id') # 原验证数据正常返回,无需修改self.data return data
然后更新视图代码,直接从序列化器实例获取已查询好的Category:
class SearchView(generics.GenericAPIView): def get(self, request): serializer = SearchSerializer(data=request.query_params) if serializer.is_valid(): # 直接获取序列化器中已缓存的Category实例,无需重复查询 category = serializer.category # TODO: 执行你的业务逻辑 return Response({'success': True}) return Response(serializer.errors)
另一种简洁方案:使用PrimaryKeyRelatedField
如果你的场景允许,也可以用DRF内置的PrimaryKeyRelatedField来自动处理存在性验证和实例查询,代码会更简洁:
class SearchSerializer(serializers.Serializer): # 自动验证category_id对应的实例存在,且返回的是Category对象 category = serializers.PrimaryKeyRelatedField(queryset=Category.objects.all()) search_term = serializers.CharField(required=False)
此时视图中直接从验证后的数据里获取实例即可:
class SearchView(generics.GenericAPIView): def get(self, request): serializer = SearchSerializer(data=request.query_params) if serializer.is_valid(): category = serializer.validated_data['category'] # TODO: 执行你的业务逻辑 return Response({'success': True}) return Response(serializer.errors)
这种方案的优势是DRF帮你封装了所有验证逻辑,不需要自己编写validate方法,且validated_data中直接就是Category实例。
内容的提问来源于stack exchange,提问作者Arun
相关产品推荐
相关产品推荐

