B. Almeida
B. Almeida

Reputation: 385

How to return objects by popularity that was calculated with django-hitcount

I have itens in my app that I want to be returned by "popularity". This popularity meaning the number of views the item has. I'm using django-hitcount to do this. I saw here how I could get the number of hits of each object. But I don't want to load all my Item objects to memory to accomplish what I want because it's an unnecessary overload. I want to return the N most popular itens to be passed to the view and the access number of each item.

My Item model is as bellow

class Item(models.Model, HitCountMixin):
    nome = models.CharField(max_length=255, unique=True)
    slug = models.SlugField(max_length=255, null=True)
    imagem = models.ImageField(upload_to='itens/item/', null=True, blank=True)
    descricao = RichTextUploadingField(null=True, blank=True)
    categoria = models.ForeignKey(Categoria)
    hit_count_generic = GenericRelation(
        HitCount, object_id_field='object_pk',
        related_query_name='hit_count_generic_relation')

    def __str__(self):
        return '{}'.format(self.nome)

    def get_absolute_url(self):
        from django.urls import reverse
        return reverse('itens:detail_item', args=[str(self.slug)])

At first, in my View I was trying to get the most popular itens with this function

def get_most_popular_itens(amount):
    return Item.objects.order_by('-hit_count.hits')[:amount]

But it didn't work. I couldn't understand how this contenttype/generic relationship works. So, I saw how the database tables were and managed to do something functional (see bellow). But it has one problem. The queryset returned isn't ordered by the number of views and I don't have access to this number. Even more, it seems to me that my solution is at least bad. So, I wanted any idea on how I could improve that, maybe taking some advantage from the Generic Relationship?

def get_most_popular_itens(amount):
    ct = ContentType.objects.get_for_model(Item)
    hit_counts = HitCount.objects.filter(content_type_id=ct.id).order_by('-hits')[:amount]
    items = []
    for hit in hit_counts:
        items.append(hit.object_pk)
    return Item.objects.filter(id__in=items)

Upvotes: 1

Views: 526

Answers (1)

Tim
Tim

Reputation: 1357

This should work:

Item.objects.all().order_by('-hit_count_generic__hits')

Upvotes: 1

Related Questions