Django Graphene嵌套过滤无匹配子数据时不返回父记录方法
问题原因
你当前的实现存在两个核心问题:
- GraphQL执行顺序是自顶向下的,先解析父级
purchases字段拿到所有采购订单,再逐个解析每个订单下的products子字段。你把产品名过滤参数写在子级products上,父级查询时完全感知不到这个过滤条件,自然会把当前用户的所有采购订单全查出来。 - 你自定义的
resolve_products方法原本没有使用传入的过滤参数,即使后续过滤器做了一层子项过滤,本质还是在已查出的父订单范围内筛选子产品,不会回过去剔除没有匹配产品的父订单。
修复步骤
1. 给采购订单类型新增跨表产品过滤能力
修改Purchases类的Meta.filter_fields配置,增加关联产品表的过滤规则,支持在查询采购订单时直接按下属产品名筛选:
class Purchases(DjangoObjectType): id = graphene.ID(source='pk', required=True) products = ArtsyConnectionField(PurchasesProducts) class Meta: model = purchase_orders interfaces = (relay.Node,) filter_fields = { 'date': ['gt', 'lt', 'isnull'], 'username': ['icontains'], # 新增跨关联表的产品名过滤 'products__product_name': ['icontains'] } connection_class = ArtsyConnection
2. 调整采购订单查询逻辑,提前过滤无匹配产品的订单
修改resolve_purchases方法,识别产品名过滤参数,在查询采购订单阶段就通过外键关联筛掉不存在匹配产品的订单,注意加distinct()避免一个订单下多个匹配产品时返回重复数据:
@staticmethod def resolve_purchases(self, info, **kwargs): queryset = purchase_orders.objects.filter(user_id=info.context.user.id) # 提取产品名过滤参数 product_name_keyword = kwargs.get('products_ProductName_Icontains') if product_name_keyword: queryset = queryset.filter( products__product_name__icontains=product_name_keyword ).distinct() # 保留原有排序、日期过滤逻辑 return queryset.order_by("-date")
3. 补全子产品解析的过滤逻辑
修改resolve_products方法,把传入的过滤参数应用到产品查询上,保证每个订单下返回的产品也只有匹配项:
@staticmethod def resolve_products(self, info, **kwargs): queryset = purchase_orders_products.objects.filter(order_id=self.id) product_name_keyword = kwargs.get('productName_Icontains') if product_name_keyword: queryset = queryset.filter(product_name__icontains=product_name_keyword) return queryset.order_by('product_name').all()
4. 调整GraphQL查询参数位置
将产品名过滤参数上移到父级purchases查询上(子级可以保留相同参数做双重校验),修改后的查询如下:
{ dateFilterList purchases(first: 15, after: "", products_ProductName_Icontains: "access") { pageCursors { ... } edges { node { id username ... products(productName_Icontains: "access") { edges { node { id productId productName productNumber } } } } } } }
最终效果
修改后查询时,没有任何匹配产品的采购订单(比如你示例中username为ThisIsUsername、products.edges为空的订单)会在数据库查询阶段就被过滤掉,返回结果里只会保留包含匹配产品的采购订单,每个订单下的产品列表也仅展示符合搜索条件的产品项,不会再出现空产品列表的无效订单。
内容的提问来源于stack exchange,提问作者Ross
相关产品推荐
相关产品推荐

