from typing import TypeVar from django.db.models import Avg, OuterRef, IntegerField, Value, Subquery from django.db.models.functions import Coalesce from django.db import models T = TypeVar('T') class PublicationQuerySet(models.QuerySet[T]): def with_score(self): qs = self qs = qs.annotate(average_score=Coalesce(Avg("ratings__score"), 0.0)) return qs def only_publish(self): from .models import Publication qs = self return qs.filter(status=Publication.StatusVarioations.PUBLIC.value) def with_user_score(self, user): from .models import Rating user_rating = Rating.objects.filter( publication=OuterRef("pk"), user=user ).values("score")[:1] return self.annotate( current_user_score=Coalesce( Subquery(user_rating, output_field=IntegerField()), Value(0) ) ) class PublicationManager(models.Manager[T]): def get_queryset(self): return PublicationQuerySet[T](self.model, using=self._db).with_score() def with_related(self): return self.get_queryset().select_related('user', 'category') def with_user_score(self, user): return self.get_queryset().with_user_score(user) def only_publish(self): return self.get_queryset().only_publish()