【问题标题】:How to exclude rows with empty prefetch_related field如何排除具有空 prefetch_related 字段的行
【发布时间】:2020-09-03 21:47:15
【问题描述】:

我将prefetch_relatedPrefetch 一起使用:

prefetch_qs = Offer.objects.filter(price__gt=1000)
prefetch = Prefetch('offers', queryset=prefetch_qs)

如何排除包含空商品的行?不行,因为annotate统计了所有offer(prefetch中没有过滤):

filtered_qs = Product.objects.annotate(
    offers_count=Count('offers')
).filter(
    offers_count__gt=0
).prefetch_related(
    prefetch      
)

【问题讨论】:

    标签: python django django-orm


    【解决方案1】:

    Prefetch 在产品查询之后作为第二个查询执行,因此无法根据预取过滤掉产品。您需要将预取过滤作为子查询或在您尝试创建的 Count 中重复。

    为了让 Count 起作用,请尝试以下操作:

    filtered_qs = Product.objects.annotate(
        offers_count=Count('offers', filter=Q(offers__price__gt=1000))
    ).filter(
        offers_count__gt=0
    ).prefetch_related(
        prefetch
    )
    

    为了使用子查询,您需要这样的东西:

    filtered_qs = Product.objects.annotate(
        offers_count=Subquery(
            prefetch_qs.filter(product=OuterRef('pk'))
                .values('product')
                .annotate(count=Count('pk'))
                .values('count')
        )
    ).filter(
        offers_count__gt=0
    ).prefetch_related(
        prefetch
    )
    

    子查询方法可能看起来有点难以理解为什么这样做,我试图在一些老问题here中解释它

    【讨论】:

    • 在第一种情况下,它应该是Count('offers', filter=Q(offers__price__gt=1000))。我应该在所有过滤器中添加offers__ :(
    • 子查询案例有效。但是很慢。 4-5s 而不是 1s 之前 :(
    • 平均 1200 毫秒。现在我想找到将offer__ 添加到我所有过滤器的方法。可能我应该使用 dict 并将 offer__ 添加到它的键中以获取新的 dict
    • @alexandr-tatarinov 提到的SubqueryCount 方法的性能仍然很差吗?我会首先尝试调试子查询方法对性能的影响(学习更多 SQL 永远不会迟到),然后才返回 count+filter 作为最后的手段。
    • @alexandr-tatarinov 方法也很长。 Django 调试工具栏显示两个大的慢查询。
    【解决方案2】:

    补充@Todor 答案:您可以创建自定义子查询类型以简化第二种方法并允许重用。

    class SubqueryCount(Subquery):
        template = '(SELECT COUNT(*) FROM (%(subquery)s) _sub)'
        output_field = IntegerField()
    
    filtered_qs = Product.objects.annotate(
        offers_count=SubqueryCount(prefetch_qs.filter(product=OuterRef('pk'))
    ).filter(
        offers_count__gt=0
    ).prefetch_related(
        prefetch
    )
    

    【讨论】:

    • bolshoe spasibo :)
    猜你喜欢
    • 1970-01-01
    • 2019-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-29
    • 2010-10-11
    • 2018-09-25
    • 2011-12-14
    相关资源
    最近更新 更多