[Django]-Django weighted query (annotated values)

3👍

First, you would need to make sure that division would yield floats (without rounding). You would need something like this (disgracefully stolen here):

ExpressionWrapper(
    (F('views') / Decimal(50.0), 
    output_field=FloatField()),
)

So, query would look like this:

products = (Media.objects
    .exclude(is_deleted=1)
    .filter(Q(category__category__in=categories) | Q(tags__tag__title=query))
    .annotate(order_count = Count('orders', distinct=True))
    .annotate(comment_count = Count('comments', distinct=True))
    .annotate(like_count = Count('likes', distinct=True))
    .annotate(weight = Count(0))
    .annotate(
        initial_weight=ExpressionWrapper(
            F('order_count') * 40 + F('comment_count') * 4 +
            F('like_count') * 4 + F('clicks'),
            output_field=FloatField()
        )
     )
    .annotate(
        views_divided=ExpressionWrapper((F('views') / Decimal(50.0), 
                                        output_field=FloatField()))
     )
    .annotate(weight=F('initial_weight') - F('views_divided'))
    .distinct())

Looks ugly, but should work (I think).

On the side note – if you only need to calculate weight, you don’t actually have to use prefetch_related and select_realted, django will take care of that stuff itself (however, that’s just my speculation – if you actually use those foreign keys later in the code, then it’s justified).

Leave a comment