如何在drf中,优雅地处理关联数据 2025年10月9日 38 代码厨子 我在写序列化器时候,需要用related_name来找到外键链接的数据,我如何能过进行筛选呢? 例如一个场景:我需要取出来的外键关联数据要排除所有软删除的记录,这就麻烦了,我要用自定义序列化器才行,太麻烦了,于是,我就想了几个办法。 在DRF中有一些更优雅和高效的方式来处理关联数据的筛选。以下是几种改进方案: ### 1. 使用Prefetch优化查询性能 你的当前写法会导致额外的数据库查询,使用`prefetch_related`可以优化查询性能: ```python from django.db.models import Prefetch # 在视图中使用 queryset = TradeTrack.objects.prefetch_related( Prefetch( 'rn_trade_track_goods', # 这里使用外键的related_name queryset=TradeTrackGoods.objects.filter(is_deleted=False), to_attr='filtered_goods' # 自定义属性名 ) ) # 在序列化器中 class TradeTrackReadSerializer(serializers.ModelSerializer): rn_trade_track_goods = TradeTrackGoodsReadSerializer(source='filtered_goods', many=True, read_only=True) class Meta: model = TradeTrack fields = "__all__" ``` ### 2. 利用模型管理器 如果`is_deleted=False`是常用筛选条件,可以在模型中定义一个管理器: ```python # models.py class TradeTrackGoodsManager(models.Manager): def active(self): return self.filter(is_deleted=False) class TradeTrackGoods(models.Model): # 你的字段定义... objects = TradeTrackGoodsManager() # 序列化器中 class TradeTrackReadSerializer(serializers.ModelSerializer): rn_trade_track_goods = serializers.SerializerMethodField() @staticmethod def get_rn_trade_track_goods(obj: TradeTrack): # 使用自定义管理器方法 return TradeTrackGoodsReadSerializer(obj.rn_trade_track_goods.active(), many=True).data class Meta: model = TradeTrack fields = "__all__" ``` ### 3. 使用DRF的RelatedField 如果逻辑更复杂,可以自定义一个RelatedField: ```python class FilteredTradeTrackGoodsField(serializers.RelatedField): def to_representation(self, value): return TradeTrackGoodsReadSerializer(value).data def get_queryset(self): return TradeTrackGoods.objects.filter(is_deleted=False) class TradeTrackReadSerializer(serializers.ModelSerializer): rn_trade_track_goods = FilteredTradeTrackGoodsField(many=True, read_only=True) class Meta: model = TradeTrack fields = "__all__" ``` ### 选择建议: - 如果关注性能,推荐第一种方案(Prefetch),可以减少数据库查询次数 - 如果`is_deleted=False`是项目中的通用筛选条件,推荐第二种方案(模型管理器),便于统一维护 - 如果需要更复杂的过滤逻辑,第三种方案(自定义RelatedField)更灵活 这些方法都比直接在SerializerMethodField中写查询更符合DRF的设计理念,也更易于维护和扩展。