"""Utils QuerySet Mixins""" from django.db import models from django.db.models import Q, Sum, F from functools import reduce from operator import add from utils.methods import get_contenttype class ContentTypeQuerySetMixin(models.QuerySet): """QuerySet for ContentType""" def by_object_id(self, object_id: int): """Filter by object_id""" return self.filter(object_id=object_id) def by_content_type(self, app_label: str = 'favorites', model: str = 'favorites'): """Filter QuerySet by ContentType.""" return self.filter(content_type=get_contenttype(app_label=app_label, model=model)) class RelatedObjectsCountMixin(models.QuerySet): """QuerySet for ManyToMany related count filter""" def _get_related_objects_names(self): """Get all related objects (with reversed)""" related_objects_names = [] for related_object in self.model._meta.related_objects: if isinstance(related_object, models.ManyToManyRel): related_objects_names.append(related_object.name) return related_objects_names def _annotate_related_objects_count(self): """Annotate all related objects to queryset""" annotations = {} for related_object in self._get_related_objects_names(): annotations[f"{related_object}_count"] = models.Count(f"{related_object}") return self.annotate(**annotations) def filter_related_gt(self, count): """QuerySet filter by related objects count""" q_objects = Q() for related_object in self._get_related_objects_names(): q_objects.add(Q(**{f"{related_object}_count__gt": count}), Q.OR) return self._annotate_related_objects_count().filter(q_objects) def filter_all_related_gt(self, count): """Queryset filter by all related objects count""" exp =reduce(add, [F(f"{related_object}_count") for related_object in self._get_related_objects_names()]) return self._annotate_related_objects_count()\ .annotate(all_related_count=exp)\ .filter(all_related_count__gt=count)