我使用自定义预取对象只获取一些相关对象,例如:
unreleased_prefetch = Prefetch("chants", Chant.objects.with_audio())
teams = Team.objects.public().prefetch_related(unreleased_prefetch)
这很好用,但我也想知道这些对象的数量并按这些过滤。我很高兴我现在可以将queryset用作Prefetch对象的参数(因为我大量使用自定义QuerySet / Managers)。
我是否可以重用此查询,我使用条件注释以相同的方式传递给Prefetch对象?
到目前为止,我的条件注释非常难看并且看起来像这样(它与我原来的chant 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)
它有效,但非常丑陋并且具有重复的逻辑。 有没有办法将queryset传递给我以同样的方式我可以将它传递给prefetch以避免重复?
答案 0 :(得分: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
时将其存储在构造函数的字段中。