Estoy usando un objeto de captación previa personalizado para obtener solo algunos objetos relacionados, por ejemplo:
unreleased_prefetch = Prefetch("chants", Chant.objects.with_audio()) teams = Team.objects.public().prefetch_related(unreleased_prefetch)Esto funciona bien, pero también quiero saber el número de estos objetos y filtrarlos. Estoy feliz de poder usar queryset en este momento como parámetro para el objeto Prefetch (ya que uso mucho QuerySets/Managers personalizados).
¿Hay alguna forma de reutilizar esta consulta, que pase al objeto Prefetch de la misma manera con la anotación condicional?
Hasta ahora, mi anotación condicional es bastante fea y se ve así (hace lo mismo que mi canto original con consulta/filtro personalizado 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)Funciona, pero es bastante feo y tiene lógica duplicada. ¿Hay alguna forma de pasar queryset a When de la misma manera que puedo pasarlo a prefetch para evitar duplicaciones?
No digo que esta sea la mejor práctica ni nada, pero quería proporcionar una forma potencial de lidiar con tal situación.
Digamos que tiene una clase 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)Lo que usa como gerente haciendo algo como lo siguiente, probablemente:
class Chant(models.Model): # ... objects = ChantQuerySet.as_manager() Sugeriría almacenar el filtro en el 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)Esto le da la capacidad de hacer esto:
Chant.objects.annotate( unreleased_count=Count(Case( When(ChantQuerySet.with_audio_filter, then=1), output_field=IntegerField())) ).filter(unreleased_count__gt=0) Ahora puede cambiar el filtro solo en un lugar, si necesita hacerlo, sin tener que cambiarlo en todas partes. Para mí, tiene sentido almacenar este filtro en QuerySet y, personalmente, no veo nada de malo en eso, pero solo soy yo.
Sin embargo, una cosa que cambiaría es hacer que la propiedad with_audio_filter se almacene en caché o almacenarla en un campo en el constructor al inicializar ChantQuerySet .