Django Popularity Ranks's

Popularity and view counts management for Django objects, with optional support for Mongodb storage backed.


This app requires Python >= 2.5 and Django >= 1.0.

pip install mongoengine is required if you want to use the Mongodb backend storage, and jQuery >= 1.3 for updating scores using AJAX requests.

The Mercurial repository of the application can be cloned with this command:

hg clone

The popularity package, included in the distribution, should be placed on the PYTHONPATH.

Otherwise you can just pip install django-popularity-ranks.


Add 'popularity' to your settings.INSTALLED_APPS

Specify the backend to use in your settings:

# django model backend
POPULARITY_BACKEND = 'popularity.backends.Django'

# mongodb backend
POPULARITY_BACKEND = 'popularity.backends.Mongodb'

If POPULARITY_BACKEND is not specified then the popularity engine is disabled.

If Mongodb backend is selected you must configure the connection parameters, e.g.:

    "NAME": "dbname",
    "USERNAME": "user",
    "PASSWORD": "passwd",
    "PARAMETERS": {},

If the instance of Mongodb is executed in localhost without authentication, you can just write:

POPULARITY_MONGODB = {"NAME": "popularity"}

Specify the rankable models in your settings, e.g.:


Theese are models that can be tracked by the popularity engine.

Make theese models subclass popularity.models.RankableModel (an abstract base Django model that basically adds the reverse generic relation), e.g.:

from popularity.models import RankableModel
class Article(RankableModel):

You can customize the popularity cap for content types, e.g.:

POPULARITY_CAP = 10000 # default is 1000

This means that popularity is calculated only for the 10000 most viewed objects for each content type.

You can customize the handler that manages backend hits, e.g. if you want to hit the authenticated user while he is browsing your site, you can set:

POPULARITY_HANDLER = 'popularity.handlers.hit_user'

Sync the database:

./ syncdb

Time for hitting the backend with scores. You can do that in different ways:

  • in your code, use the shortcut function hit, providing the model instance, e.g.:

    from popularity import shortcuts

    You can set score points for the objects (default is 1):

    shortcuts.hit(obj, 2)

    Some handlers (like 'popularity.handlers.hit_user') use the current request for hitting the backend:

    shortcuts.hit(obj, 1, request=request)
  • you can use a template tag for hitting objects, e.g.:

    {% load popularity_tags %}
    {% popularity_hit object %}

    You can set score points (default is 1):

    {% popularity_hit object=3 %}

    And you can hit several objects:

    {% popularity_hit object=2 object.user another_object=5 %}
  • You can use an ajax request:

    Add the popularity urls to your

    (r'^popularity/', include('popularity.urls')),

    use the popularity_request templatetag, that takes the same arguments as popularity_hit, e.g.:

    {% popularity_request object=2 object.user another_object=5 %}

Add the cron jobs that weekly and monthly creates and updates the object ranks:

0 1 * * 1 root ./ update_popularity -p weekly
0 1 1 * * root ./ update_popularity -p monthly

If you want to prepopulate your ranks you can run the following management comamnd:

./ reset_popularity

See help for the option list.

The app provide one templatetag to populate the template context with the most popular items of a defined type, e.g.:

{% get_most_popular [model] [period] as [varname] %}

The argument period must be weekly, monthly or absolute. The argument model must be a dotted model name, a model class or a queryset.


{% get_most_popular 'auth.user' weekly as weekly_popular_users %}
{% get_most_popular User monthly as monthly_popular_users %}

The reset_popularity management command and the get_most_popular templatetag use a callback function to get a queryset of a specific model. By default, the used callback just do model.obejcts.all() but you can customize this behaviour defining a callable path in settings.POPULARITY_QUERYSET_CALLBACK. The callback takes as arguments the Django model and a patch function that can be used to join the model to corresponding content type when the queryset is ordered by rank. The default patch function can be found in popularity.shortcuts:

def patch(queryset):
    Patch a queryset that you want to order by rank.
    content_type = ContentType.objects.get_for_model(queryset.model)
    return queryset.filter(

So, if you want to exclude inactive instances from the model queryset, you can write a POPULARITY_QUERYSET_CALLBACK as follows:

def queryset_callback(model, patch):
    return patch(model.objects.filter(is_active=True))