Source code for django.db.models.aggregates

"""Classes to represent the definitions of aggregate functions."""fromdjango.core.exceptionsimportFieldErrorfromdjango.db.models.expressionsimportCase,Func,Star,Whenfromdjango.db.models.fieldsimportIntegerFieldfromdjango.db.models.functions.mixinsimport(FixDurationInputMixin,NumericOutputFieldMixin,)__all__=['Aggregate','Avg','Count','Max','Min','StdDev','Sum','Variance',]

[docs]classAggregate(Func):template='%(function)s(%(distinct)s%(expressions)s)'contains_aggregate=Truename=Nonefilter_template='%s FILTER (WHERE %%(filter)s)'window_compatible=Trueallow_distinct=Falsedef__init__(self,*expressions,distinct=False,filter=None,**extra):ifdistinctandnotself.allow_distinct:raiseTypeError("%s does not allow distinct."%self.__class__.__name__)self.distinct=distinctself.filter=filtersuper().__init__(*expressions,**extra)defget_source_fields(self):# Don't return the filter expression since it's not a source field.return[e._output_field_or_noneforeinsuper().get_source_expressions()]defget_source_expressions(self):source_expressions=super().get_source_expressions()ifself.filter:returnsource_expressions+[self.filter]returnsource_expressionsdefset_source_expressions(self,exprs):self.filter=self.filterandexprs.pop()returnsuper().set_source_expressions(exprs)defresolve_expression(self,query=None,allow_joins=True,reuse=None,summarize=False,for_save=False):# Aggregates are not allowed in UPDATE queries, so ignore for_savec=super().resolve_expression(query,allow_joins,reuse,summarize)c.filter=c.filterandc.filter.resolve_expression(query,allow_joins,reuse,summarize)ifnotsummarize:# Call Aggregate.get_source_expressions() to avoid# returning self.filter and including that in this loop.expressions=super(Aggregate,c).get_source_expressions()forindex,exprinenumerate(expressions):ifexpr.contains_aggregate:before_resolved=self.get_source_expressions()[index]name=before_resolved.nameifhasattr(before_resolved,'name')elserepr(before_resolved)raiseFieldError("Cannot compute %s('%s'): '%s' is an aggregate"%(c.name,name,name))returnc@propertydefdefault_alias(self):expressions=self.get_source_expressions()iflen(expressions)==1andhasattr(expressions[0],'name'):return'%s__%s'%(expressions[0].name,self.name.lower())raiseTypeError("Complex expressions require an alias")defget_group_by_cols(self):return[]defas_sql(self,compiler,connection,**extra_context):extra_context['distinct']='DISTINCT 'ifself.distinctelse''ifself.filter:ifconnection.features.supports_aggregate_filter_clause:filter_sql,filter_params=self.filter.as_sql(compiler,connection)template=self.filter_template%extra_context.get('template',self.template)sql,params=super().as_sql(compiler,connection,template=template,filter=filter_sql,**extra_context)returnsql,params+filter_paramselse:copy=self.copy()copy.filter=Nonesource_expressions=copy.get_source_expressions()condition=When(self.filter,then=source_expressions[0])copy.set_source_expressions([Case(condition)]+source_expressions[1:])returnsuper(Aggregate,copy).as_sql(compiler,connection,**extra_context)returnsuper().as_sql(compiler,connection,**extra_context)def_get_repr_options(self):options=super()._get_repr_options()ifself.distinct:options['distinct']=self.distinctifself.filter:options['filter']=self.filterreturnoptions

[docs]classCount(Aggregate):function='COUNT'name='Count'output_field=IntegerField()allow_distinct=Truedef__init__(self,expression,filter=None,**extra):ifexpression=='*':expression=Star()ifisinstance(expression,Star)andfilterisnotNone:raiseValueError('Star cannot be used with filter. Please specify a field.')super().__init__(expression,filter=filter,**extra)defconvert_value(self,value,expression,connection):return0ifvalueisNoneelsevalue