Django prefetch_related和Prefetch嵌套

时间:2018-07-06 13:55:00

标签: 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'))

访问模板中的userprofile.arts|length返回预订总数,但是rgggarti不返回任何内容。该怎么办?

我尝试使用filter(profile='userprofile)对自身进行过滤,但是返回错误。如果我可以自我过滤,也许可以使它正常工作?

2 个答案:

答案 0 :(得分:2)

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'
        )
    )

我还没有机会进行测试,但是应该可以。您正在不支持的外键artist上使用prefetch_related; prefetch_related是用于支持项目列表的关系。因此,您预取了subscription_set,并在演出者上使用了select_related,然后预取了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
    )
)

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

答案 1 :(得分:2)

在尼古拉斯·克鲁德·勒布朗(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()
            )
            ))

正如尼古拉斯建议的那样,subscriptionsprofile中设置的related_query_name Subscription