django prefetch_lated & 预取嵌套

zer*_*dge 3 django django-orm

我正在尝试返回每个UserProfile,其中有一对多Subscription,有一个外键 和ArtistUserProfile每个艺术家有很多ReleaseGroup,每个人拥有的未来发行组的数量UserProfile

简而言之:我想返回每个用户拥有的所有订阅的即将发布版本的总数。

然而,在我数数之前我就被困住了......

    context['test_totals'] = UserProfile.objects.prefetch_related(
        Prefetch('subscription_set', queryset=Subscription.objects.
                 prefetch_related(Prefetch('artist', queryset=Artist.objects.
                                           prefetch_related(Prefetch('release_groups',
                                             queryset=ReleaseGroup.objects.filter(
                                        release_date__gte=startdate
        ), to_attr='rggg')), to_attr='arti')), to_attr='arts'))
Run Code Online (Sandbox Code Playgroud)

在模板中访问userprofile.arts|length会返回订阅总数,但rggg不会arti返回任何内容。如何才能做到这一点?

我尝试使用 )` 对自身进行过滤filter(profile='userprofile,但这会返回错误。如果我可以自我过滤,我可能可以让它发挥作用吗?

Nic*_*anc 5

context['test_totals'] = UserProfile.objects.prefetch_related(
    Prefetch(
        'subscription_set', 
        queryset=Subscription.objects.select_related(
            'artist', 'profile').prefetch_related(
                 Prefetch(
                     'artist__release_groups',
                     queryset=ReleaseGroup.objects.filter(
                          release_date__gte=startdate
                     ), 
                     to_attr='release_groups'
                 )
            ), 
        to_attr='subscriptions'
        )
    )
Run Code Online (Sandbox Code Playgroud)

我还没有机会测试这个,但它应该有效。artist您在不支持的外键上使用 prefetch_lated ;prefetch_lated 是为了支持项目列表的关系。因此,您预取 subscription_set 并在艺术家上使用 select_lated,然后预取artist__release_groups关系。现在你应该有profile_instance.subscriptions ...subscriptions[index].artist ...subscriptions[index].artist.release_groups

*编辑:

经过与OP讨论后,我们想使用此方法,但没有使用日期过滤器。

UserProfile.objects.annotate(
    rgs=Count(
        'subscription_set__artist__release_groups',
        filter=Q(subscription_set__artist__release_groups__release_date__gte=startdate),
    distinct=True
    )
)
Run Code Online (Sandbox Code Playgroud)

真正的答案是使用django.db.models CaseandWhen作为我发现的OP。查看他的回答以获取完成的查询


zer*_*dge 5

在 Nicholas Cluade LeBlanc 的大量帮助下,以下是工作查询:

UserProfile.objects.annotate(rgs=Count(
            Case(

                When(subscriptions__artist__release_groups__release_date__gte=startdate, then=F('subscriptions__artist__release_groups__release_date')),

                When(subscriptions__artist__release_groups__release_date__lt=startdate, then=None),

                output_field=DateField()
            )
            ))
Run Code Online (Sandbox Code Playgroud)

正如尼古拉斯所建议的,subscriptionsprofile related_query_nameSubscription.