【问题标题】:Django custom prefetch and conditional annotateDjango 自定义预取和条件注释
【发布时间】:2017-09-22 07:13:17
【问题描述】:

我正在使用自定义预取对象来仅获取一些相关对象,例如:

unreleased_prefetch = Prefetch("chants", Chant.objects.with_audio())
teams = Team.objects.public().prefetch_related(unreleased_prefetch)

这很好用,但我也想知道这些对象的数量并按这些进行过滤。我很高兴我现在可以使用查询集作为预取对象的参数(因为我大量使用自定义查询集/管理器)。

有没有办法可以重用这个查询,我通过条件注释以相同的方式传递给 Prefetch 对象?

到目前为止,我的条件注释非常难看,看起来像这样(它与我原来的圣歌 with_audio 自定义查询/过滤器做同样的事情):

.annotate(
    unreleased_count=Count(Case(
        When(chants__has_audio_versions=True, chants__has_audio=True, chants__flag_reject=False,
             chants__active=False, then=1),
        output_field=IntegerField()))
).filter(unreleased_count__gt=0)

它可以工作,但是很丑陋并且有重复的逻辑。 有没有办法将查询集传递给When我可以将它传递给预取以避免重复?

【问题讨论】:

    标签: django django-queryset


    【解决方案1】:

    并不是说这是最佳实践或任何东西,而是想提供一种处理这种情况的潜在方法。

    假设你有一个ChantQuerySet 类:

    class ChantQuerySet(models.QuerySet):
        def with_audio(self):
            return self.filter(chants__has_audio_versions=True, chants__has_audio=True,
                               chants__flag_reject=False, chants__active=False)
    

    作为经理,您可能会使用它来执行以下操作:

    class Chant(models.Model):
        # ...
        objects = ChantQuerySet.as_manager()
    

    我建议将过滤器存储在QuerySet:

    from django.db.models import Q
    
    class ChantQuerySet(models.QuerySet):
        @property
        def with_audio_filter(self):
            return Q(chants__has_audio_versions=True, chants__has_audio=True,
                     chants__flag_reject=False, chants__active=False)
    
        def with_audio(self):
            return self.filter(self.with_audio_filter)
    

    这使您能够做到这一点:

    Chant.objects.annotate(
        unreleased_count=Count(Case(
            When(ChantQuerySet.with_audio_filter, then=1),
            output_field=IntegerField()))
    ).filter(unreleased_count__gt=0)
    

    现在您可以只在一处更改过滤器(如果需要),而无需在任何地方进行更改。对我来说,将此过滤器存储在 QuerySet 中是有意义的,我个人认为这没有任何问题,但这只是我自己。

    不过,我要更改的一件事是缓存 with_audio_filter 属性,或者在初始化 ChantQuerySet 时将其存储在构造函数的字段中。

    【讨论】:

    • 这并不理想,但绝对至少解决了枯燥的问题。感谢您的建议!
    猜你喜欢
    • 1970-01-01
    • 2011-10-23
    • 2015-10-21
    • 2015-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多