def _add_quality_relevance(self, qs): """Annotates query with relevance based on quality score. It is calculated by a formula: R = log(Q + 1) + 0.1 * v Where: R - Relevance; Q - Quality score (0 to 5); v - 1 if collection belongs to a partner namespace, otherwise 0. """ quality_rank_expr = ( Func(Coalesce(F('latest_version__quality_score'), 0) + 1, function='log') * CONTENT_SCORE_MULTIPLIER) vendor_rank_expr = Case( When(namespace__is_vendor=True, then=Value(VENDOR_RANK)), When(namespace__is_vendor=False, then=Value(0)), ) relevance_expr = F('quality_rank') + F('vendor_rank') return qs.annotate( quality_rank=Expr(quality_rank_expr, output_field=db_fields.FloatField()), vendor_rank=Expr(vendor_rank_expr, output_field=db_fields.FloatField()), relevance=Expr(relevance_expr, output_field=db_fields.FloatField()), )
def shop_invoices(self, shop_slug): return self.annotate( coupon_price=Coalesce( Sum('coupon_usages__price_applied', output_field=DecimalField()), Value(0)), price=F('invoice_price_with_discount') + F('logistic_price') - F('coupon_price'), weight=F('total_weight_gram'), ).filter(items__product__FK_Shop__Slug=shop_slug).order_by('-created_datetime')
class Aggregate(Func): template = '%(function)s(%(distinct)s%(expressions)s)' contains_aggregate = True name = None filter_template = '%s FILTER (WHERE %%(filter)s)' window_compatible = True allow_distinct = False empty_result_set_value = None def __init__(self, *expressions, distinct=False, filter=None, default=None, **extra): if distinct and not self.allow_distinct: raise TypeError("%s does not allow distinct." % self.__class__.__name__) if default is not None and self.empty_result_set_value is not None: raise TypeError(f'{self.__class__.__name__} does not allow default.') self.distinct = distinct self.filter = filter self.default = default super().__init__(*expressions, **extra) def get_source_fields(self): # Don't return the filter expression since it's not a source field. return [e._output_field_or_none for e in super().get_source_expressions()] def get_source_expressions(self): source_expressions = super().get_source_expressions() if self.filter: return source_expressions + [self.filter] return source_expressions def set_source_expressions(self, exprs): self.filter = self.filter and exprs.pop() return super().set_source_expressions(exprs) def resolve_expression(self, query=None, allow_joins=True, reuse=None, summarize=False, for_save=False): # Aggregates are not allowed in UPDATE queries, so ignore for_save c = super().resolve_expression(query, allow_joins, reuse, summarize) c.filter = c.filter and c.filter.resolve_expression(query, allow_joins, reuse, summarize) if not summarize: # Call Aggregate.get_source_expressions() to avoid # returning self.filter and including that in this loop. expressions = super(Aggregate, c).get_source_expressions() for index, expr in enumerate(expressions): if expr.contains_aggregate: before_resolved = self.get_source_expressions()[index] name = before_resolved.name if hasattr(before_resolved, 'name') else repr(before_resolved) raise FieldError("Cannot compute %s('%s'): '%s' is an aggregate" % (c.name, name, name)) if (default := c.default) is None: return c if hasattr(default, 'resolve_expression'): default = default.resolve_expression(query, allow_joins, reuse, summarize) c.default = None # Reset the default argument before wrapping. coalesce = Coalesce(c, default, output_field=c._output_field_or_none) coalesce.is_summary = c.is_summary return coalesce
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) payroll_start_date = self.request.GET['dateFrom'] payroll_end_date = self.request.GET['dateTo'] filtered_lessons = Lesson.objects.filter( Q(start_date__gte=payroll_start_date, start_date__lte=payroll_end_date), Q(instructor=F('instructor'))) instructors = Instructor.objects.filter( Q(active=True), Q(lessons=F('lessons')), Q(lessons__start_date__gte=payroll_start_date, lessons__start_date__lte=payroll_end_date)).prefetch_related( Prefetch('lessons', filtered_lessons)).annotate( single_lessons_count=Count( 'lessons', filter=Q(lessons__group_lesson=False)), single_lessons_duration=Sum( 'lessons__duration', filter=Q(lessons__group_lesson=False)), group_lessons_count=Count( 'lessons', filter=Q(lessons__group_lesson=True)), group_lessons_duration=Sum( 'lessons__duration', filter=Q(lessons__group_lesson=True)), single_lessons_value=ExpressionWrapper( Coalesce(F('single_lessons_duration'), Value(0.0)) * Coalesce(F('pay_rate_single'), Value(0.0)), output_field=DecimalField(decimal_places=2)), group_lessons_value=ExpressionWrapper( Coalesce(F('group_lessons_duration'), Value(0.0)) * Coalesce(F('pay_rate_group'), Value(0.0)), output_field=DecimalField( decimal_places=2))).annotate( payroll_sum=F('single_lessons_value') + F('group_lessons_value')) context['instructors'] = instructors return context
def subquery_count_distinct(subquery, column): """ Returns a coalesced count of the number of distinct values in the specified column of the specified subquery. Usage example: Course.objects.annotate( num_activities=subquery_count_distinct( subquery=Section.objects.filter(course_id=OuterRef("id")), column="activity" ) ) # counts the number of distinct activities each course has """ return Coalesce( Subquery( subquery.annotate(common=Value(1)).values("common").annotate( count=Count(column, distinct=True)).values("count")), 0, )
def test_openshift_cluster_with_cluster_access_view(self): """Test endpoint runs with a customer owner.""" with schema_context(self.schema_name): expected = (OCPCostSummaryP.objects.annotate( **{ "value": F("cluster_id"), "ocp_cluster_alias": Coalesce(F("cluster_alias"), "cluster_id") }).values("value", "ocp_cluster_alias").distinct().filter( cluster_id__in=["OCP-on-AWS"]).count()) # check that the expected is not zero self.assertTrue(expected) url = reverse("openshift-clusters") response = self.client.get(url, **self.headers) self.assertEqual(response.status_code, status.HTTP_200_OK) json_result = response.json() self.assertIsNotNone(json_result.get("data")) self.assertIsInstance(json_result.get("data"), list) self.assertEqual(len(json_result.get("data")), expected)
class OCPClustersView(generics.ListAPIView): """API GET list view for Openshift clusters.""" queryset = (OCPCostSummaryP.objects.annotate( **{ "value": F("cluster_id"), "ocp_cluster_alias": Coalesce(F("cluster_alias"), "cluster_id") }).values( "value", "ocp_cluster_alias").distinct().filter(cluster_id__isnull=False)) serializer_class = ResourceTypeSerializer permission_classes = [OpenShiftAccessPermission] filter_backends = [filters.OrderingFilter, filters.SearchFilter] ordering = ["value", "ocp_cluster_alias"] search_fields = ["value", "ocp_cluster_alias"] @method_decorator(vary_on_headers(CACHE_RH_IDENTITY_HEADER)) def list(self, request): # Reads the users values for Openshift cluster id and displays values related to what the user has access to supported_query_params = ["search", "limit"] user_access = None error_message = {} # Test for only supported query_params if self.request.query_params: for key in self.request.query_params: if key not in supported_query_params: error_message[key] = [{"Unsupported parameter"}] return Response(error_message, status=status.HTTP_400_BAD_REQUEST) if request.user.admin: return super().list(request) if request.user.access: user_access = request.user.access.get("openshift.cluster", {}).get("read", []) # checks if the access exists, and the user has wildcard access if user_access and user_access[0] == "*": return super().list(request) self.queryset = self.queryset.filter(cluster_id__in=user_access) return super().list(request)
def _add_relevance(self, qs): """Annotates query with relevance rank and its constituent values. Relevance is calculated by a formula: R = Sr + Dr + Qr, where R - relevance; Sr - search rank (from 0 to 1); Dr - download rank; Qr - quality rank; ts_rank() Sr = ------------- ts_rank() + 1 For more details on search rank see `_add_search_rank` function. Download rank is calculated by a formula: ln(cd + 1) Dr = 0.4 * -------------- ln(cd + 1) + 1 Quality rank is calculated by a formula: Qr = 0.2 * log(Q + 1) """ c = 'repository__community_score' d = 'repository__download_count' # ln((MOD*c + MIN) * d + 1) # where c = community_score and d = download_count # We're using the community_score as a modifier to the download count # instead of just allocating a certain number of points based on the # score. The reason for this is that the download score is # a logaritmic scale so adding a fixed number of points ended up # boosting scores way too much for content with low numbers of # downloads. This system allows for the weight of the community score # to scale with the number of downloads download_count_ln_expr = Func( (((Coalesce(F(c), 0) * COMMUNITY_SCORE_MODIFIER) + COMMUNITY_SCORE_MODIFIER_MIN) * F(d)) + 1, function='ln') download_rank_expr = (F('download_count_ln') / (1 + F('download_count_ln')) * DOWNLOAD_RANK_MULTIPLIER) q = 'repository__quality_score' # This function is better than using a linear function because it # makes it so that the effect of losing the first few points is # relatively minor, which reduces the impact of errors in scoring. quality_rank_expr = (Func(Coalesce(F(q), 0) + 1, function='log') * CONTENT_SCORE_MULTIPLIER) relevance_expr = (F('search_rank') + F('download_rank') + F('quality_rank')) return qs.annotate( download_count_ln=Expr(download_count_ln_expr, output_field=db_fields.FloatField()), download_rank=Expr(download_rank_expr, output_field=db_fields.FloatField()), quality_rank=Expr(quality_rank_expr, output_field=db_fields.FloatField()), relevance=Expr(relevance_expr, output_field=db_fields.FloatField()), )