Source code for queryable_properties.properties.annotation

# -*- coding: utf-8 -*-

from django.db.models import Q

from ..utils.internal import QueryPath
from .base import QueryableProperty
from .mixins import AnnotationGetterMixin, BooleanMixin


[docs] class AnnotationProperty(AnnotationGetterMixin, QueryableProperty): """ A property that is based on a static annotation that is even used to provide getter values. """ def __init__(self, annotation, **kwargs): """ Initialize a new property that gets its value by retrieving an annotated value from the database. :param annotation: The static annotation to use to determine the value of this property. """ super(AnnotationProperty, self).__init__(**kwargs) self.annotation = annotation
[docs] def get_annotation(self, cls): return self.annotation
[docs] class AggregateProperty(AnnotationProperty): """ A property that is based on an aggregate that is used to provide both queryset annotations as well as getter values. """ def __init__(self, aggregate, **kwargs): """ Initialize a new property that gets its value by retrieving an aggregated value from the database. :param django.db.models.Aggregate aggregate: The aggregate to use to determine the value of this property. """ super(AggregateProperty, self).__init__(aggregate, **kwargs)
[docs] def get_value(self, obj): return self.get_queryset_for_object(obj).aggregate(**{self.name: self.annotation})[self.name]
[docs] class RelatedExistenceCheckProperty(BooleanMixin, AnnotationGetterMixin, QueryableProperty): """ A property that checks whether related objects to the one that uses the property exist in the database and returns a corresponding boolean value. Supports queryset filtering and ``CASE``/``WHEN``-based annotating. """ def __init__(self, relation_path, negated=False, **kwargs): """ Initialize a new property that checks for the existence of related objects. :param str relation_path: The path to the object/field whose existence is to be checked. May contain the lookup separator (``__``) to check for more remote relations. """ super(RelatedExistenceCheckProperty, self).__init__(**kwargs) self.query_path = QueryPath(relation_path) + 'isnull' self.negated = negated @property def _base_condition(self): """ Return the base condition for the existence check that can be applied to a queryset of the model this property is defined on for the positive (existence check rather than non-existence check) case. :return: The base condition for this property. :rtype: django.db.models.Q """ return self.query_path.build_filter(False)
[docs] def get_value(self, obj): condition = self._base_condition if self.negated: condition.negate() return self.get_queryset_for_object(obj).filter(condition).exists()
def _get_condition(self, cls): # Perform the filtering via a subquery to avoid any side-effects that may be introduced by JOINs. condition = Q(pk__in=self.get_queryset(cls).filter(self._base_condition)) if self.negated: condition.negate() return condition