80 lines
3.0 KiB
Python
80 lines
3.0 KiB
Python
"""Utils QuerySet Mixins"""
|
|
from functools import reduce
|
|
from operator import add
|
|
|
|
from django.db import models
|
|
from django.db.models import Q, F
|
|
|
|
from utils.methods import get_contenttype
|
|
from utils.models import TJSONField
|
|
|
|
|
|
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)
|
|
|
|
|
|
class TranslationQuerysetMixin(models.QuerySet):
|
|
|
|
def _get_translatable_fields(self):
|
|
"""Get translatable fields from model."""
|
|
translatable_fields = []
|
|
model = self.model
|
|
for field in model._meta.fields:
|
|
field_name = field.name
|
|
if isinstance(field, TJSONField):
|
|
translatable_fields.append(field_name)
|
|
return translatable_fields
|
|
|
|
def _get_translatable_field_filters(self, locale: str):
|
|
"""Generate filters for filtering TJSON objects that has necessary locale."""
|
|
return {f'{field}__has_key': locale for field in self._get_translatable_fields()}
|
|
|
|
def has_translation(self, locale: str):
|
|
"""Filter objects by locale from request."""
|
|
return self.filter(**self._get_translatable_field_filters(locale))
|