Django REST Framework如何排除嵌套序列化器结果为空的实例
解决方法
你当前的过滤逻辑仅作用于嵌套的观测数据层面,父级Site的查询是全量返回的,所以即使观测被过滤为空,Site实例依然会被序列化输出。可以通过以下两种方案实现需求:
方案1:视图层预过滤QuerySet(推荐,性能最优)
在数据库查询阶段就直接排除没有符合条件观测的Site,同时提前预过滤关联的观测数据,避免序列化阶段重复过滤,性能远高于后续序列化层过滤。
修改视图的get_queryset方法即可:
from django.db.models import Prefetch from .models import Observation class SiteList(generics.ListAPIView): serializer_class = SiteSerializer def get_serializer_context(self): context = super(SiteList, self).get_serializer_context() context.update({"projName": self.kwargs["name"]}) return context def get_queryset(self): proj_name = self.kwargs["name"] # 复用你已有的过滤逻辑,生成符合条件的观测查询集 filtered_obs = filter_site_observations( Observation.objects.all(), self.request, proj_name ) # 预加载过滤后的观测数据,同时仅保留存在符合条件观测的站点 return Site.objects.prefetch_related( Prefetch("site_observations", queryset=filtered_obs) ).filter( site_observations__in=filtered_obs ).distinct().order_by("pk")
注:使用该方案后,你原来在FilteredObsListSerializer中的过滤逻辑可以直接删除,避免重复执行过滤操作。
方案2:序列化层结果过滤(适合过滤逻辑无法提前到查询层的场景)
如果你的filter_site_observations逻辑依赖仅序列化阶段才能获取的上下文,无法在数据库查询阶段执行,可以在序列化后过滤空结果:
第一步,重写Site序列化器的to_representation方法,将观测为空的站点返回为None:
class SiteSerializer(GeoFeatureModelSerializer): site_observations = ObsFilterSerializer(many=True) class Meta: model = Site geo_field = "geometry" fields = ("id", "name", "geometry", "site_observations") def to_representation(self, instance): rep = super().to_representation(instance) # 观测列表为空时返回None,后续统一过滤 if not rep["site_observations"]: return None return rep
第二步,重写视图的list方法,过滤掉所有空的None条目:
class SiteList(generics.ListAPIView): queryset = Site.objects.all().order_by("pk") serializer_class = SiteSerializer def get_serializer_context(self): context = super(SiteList, self).get_serializer_context() context.update({"projName": self.kwargs["name"]}) return context def list(self, request, *args, **kwargs): response = super().list(request, *args, **kwargs) # 过滤观测为空的站点 response.data = [item for item in response.data if item is not None] return response
内容的提问来源于stack exchange,提问作者Peter Donovan
相关产品推荐
相关产品推荐

