Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

198
Visualizações
Django custom prefetch and conditional annotate

I am using custom prefetch object to get only some related objects, ex:

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

This works well, but I also want to know count of these objects and filter by these. I am happy that I can at the moment use queryset as parameter to Prefetch object (as I heavily use custom QuerySets/Managers).

Is there way how I can reuse this query, that I pass to Prefetch object same way with conditional annotate?

So far my conditional annotate is quite ugly and looks like this (it does same thing as my original chant with_audio custom query/filter):

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

It works, but is quite ugly and has duplicated logic. Is there way to pass queryset to When same way I can pass it to prefetch to avoid duplications?

over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

Not saying this is the best practice or anything, but wanted to provide a potential way of dealing with such a situation.

Let's say you have a ChantQuerySet class:

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)

Which you use as a manager doing something like below, probably:

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

I would suggest storing the filter in the 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)

This gives you the ability to do this:

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

Now you are able to change the filter only in one place, should you need to do so, without having to change it everywhere. To me it makes sense to store this filter in the QuerySet and personally I see nothing wrong with that, but that's just me.

One thing that I'd change though, is to either make the with_audio_filter property cached, or store it in a field in the constructor when initializing ChantQuerySet.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda