DRF验证最外层序列化器时丢失内部序列化对象问题求助
解决DRF嵌套序列化器验证后内部对象丢失的问题
我完全懂你遇到的这个糟心问题——用嵌套序列化器接收搜索参数,结果外层序列化器验证完,内层的序列化对象直接丢了,根本没法用它来构建OR逻辑的查询。结合你用的Django 2.0、DRF 3.7.7版本,给你几个针对性的解决方案:
方案1:自定义validate方法,手动留存内层序列化对象
DRF默认只会把内层序列化器的验证后字典数据放到外层的validated_data里,不会保留内层序列化器实例。但我们可以在validate方法里手动把内层实例存下来,后续就能直接调用它的属性了。
举个实际代码例子,假设你的搜索过滤规则用嵌套序列化器定义:
from rest_framework import serializers from django.db.models import Q # 内层过滤规则序列化器 class SearchFilterSerializer(serializers.Serializer): name = serializers.CharField(required=False) email = serializers.EmailField(required=False) age = serializers.IntegerField(required=False) # 外层请求序列化器 class SearchRequestSerializer(serializers.Serializer): filters = SearchFilterSerializer(required=False) def validate(self, data): # 手动验证并保存内层序列化器实例 filters_data = data.get('filters', {}) self.filters_serializer = SearchFilterSerializer(data=filters_data) self.filters_serializer.is_valid(raise_exception=True) return data
然后在视图里,就能直接用留存的内层实例获取验证后的数据,构建OR查询:
from rest_framework.views import APIView from rest_framework.response import Response from .models import YourTargetModel class SearchAPIView(APIView): def post(self, request): serializer = SearchRequestSerializer(data=request.data) serializer.is_valid(raise_exception=True) # 从留存的内层序列化器拿验证后的参数 valid_filters = serializer.filters_serializer.validated_data query = Q() # 遍历非空参数构建OR逻辑 for field, value in valid_filters.items(): if value is not None: query |= Q(**{field: value}) results = YourTargetModel.objects.filter(query) # 这里可以添加结果序列化返回的逻辑 return Response({ "total": results.count(), "data": [obj.to_dict() for obj in results] # 假设模型有to_dict方法 })
方案2:简化结构,直接用外层序列化器承载所有搜索字段
如果你的搜索规则没有复杂的嵌套层级,完全可以把所有搜索字段直接放到外层序列化器里,这样绕开嵌套序列化器的问题,代码更简洁:
class SearchRequestSerializer(serializers.Serializer): name = serializers.CharField(required=False) email = serializers.EmailField(required=False) age = serializers.IntegerField(required=False)
视图里直接处理validated_data构建OR查询:
def post(self, request): serializer = SearchRequestSerializer(data=request.data) serializer.is_valid(raise_exception=True) query = Q() for field, value in serializer.validated_data.items(): if value: query |= Q(**{field: value}) results = YourTargetModel.objects.filter(query) # 返回结果
补充:为什么会出现内部对象丢失?
DRF的嵌套字段验证流程是:先调用内层序列化器完成验证,然后只把内层的validated_data(字典格式)提取到外层的validated_data中,不会保留内层序列化器的实例。所以如果需要用到内层实例的其他能力,就得手动在validate方法里留存。
内容的提问来源于stack exchange,提问作者Alberto Chiusole
相关产品推荐
相关产品推荐

