Beispiel #1
0
    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')
Beispiel #3
0
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
Beispiel #4
0
    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
Beispiel #5
0
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,
    )
Beispiel #6
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)
Beispiel #7
0
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)
Beispiel #8
0
    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()),
        )