This Django application will help you to create your own badge system on your website.
It has been used on Ulule to create our own badge mechanism.
$ pip install django-badgify
Add badgify
to your INSTALLED_APPS
in settings.py
:
INSTALLED_APPS = (
# ...
'badgify',
)
Synchronize the database:
$ python manage.py migrate badgify
Create a badgify_recipes.py
file in your Django application:
$ cd path/to/your/django/app
$ touch badgify_recipes.py
Open this file and import badgify.recipe.BaseRecipe class and badgify module:
from badgify.recipe import BaseRecipe
import badgify
Create and register your recipe classes:
class PythonLoverRecipe(BaseRecipe):
pass
class JSLoverRecipe(BaseRecipe):
pass
# Per class
badgify.register(PythonLoverRecipe)
badgify.register(JSLoverRecipe)
# All at once in a list
badgify.register([PythonLoverRecipe, JSLoverRecipe])
A recipe class must implement:
name
class attribute- The badge name (humanized).
image
property- The badge image/logo as a file object.
A recipe class may implement:
slug
class attribute- The badge slug (used internally and in URLs). If not provided, it will be auto-generated based on the badge name.
description
class attribute- The badge description (short). It not provided, value will be blank.
user_ids
propertyQuerySet
returning User IDs likely to be awarded. You must return aQuerySet
and not just a Python list or tuple. You can usevalues_list('id', flat=True)
.
db_read
class attribute- The database alias on which to perform read queries.
Defaults to
django.db.DEFAULT_DB_ALIAS
.
batch_size
class attribute- How many
Award
objects to create at once. Defaults toBADGIFY_BATCH_SIZE
(500
).
Example:
from django.contrib.staticfiles.storage import staticfiles_storage
from badgify.recipe import BaseRecipe
import badgify
from .models import MyCustomUser
class PythonLoverRecipe(BaseRecipe):
"""
People loving Python.
"""
name = 'Python Lover'
slug = 'python-lover'
description = 'People loving Python programming language'
@property
def image(self):
return staticfiles_storage.open('python-lover.png')
@property
def user_ids(self):
return (MyCustomUser.objects.filter(love_python=True)
.values_list('id', flat=True))
class JSLoverRecipe(BaseRecipe):
"""
People loving JS.
"""
name = 'JS Lover'
slug = 'js-lover'
description = 'People loving JS programming language'
@property
def image(self):
return staticfiles_storage.open('js-lover.png')
@property
def user_ids(self):
return (MyCustomUser.objects.filter(love_js=True)
.values_list('id', flat=True))
class JavaLoverRecipe(BaseRecipe):
"""
People loving Java.
"""
name = 'Java Lover'
slug = 'java-lover'
description = 'People loving Java programming language'
@property
def image(self):
return staticfiles_storage.open('java-lover.png')
badgify.register([
PythonLoverRecipe,
JSLoverRecipe,
JavaLoverRecipe,
])
Once you have implemented and registered your recipe classes, you can invoke available commands bellow:
# Create badges from recipes
$ python manage.py badgify_sync badges
# Update badges from recipes
$ python manage.py badgify_sync badges --update
# Create awards
$ python manage.py badgify_sync awards
# Create awards bypassing signals (improve performances)
$ python manage.py badgify_sync awards --disable-signals
# Only create awards for "python" badge
$ python manage.py badgify_sync awards --badges python
# Only create awards for "python" and "go" badges
$ python manage.py badgify_sync awards --badges "python go"
# Create awards for all badges, except "php"
$ python manage.py badgify_sync awards --exclude-badges php
# Create awards for all badges, except "php" and "java"
$ python manage.py badgify_sync awards --exclude-badges "php java"
# Denormalize Badge.users.count() into Badge.users_count field
$ python manage.py badgify_sync counts
# Only denormalize counts for "python" badge
$ python manage.py badgify_sync counts --badges python
# Denormalize counts for all badges, except "php"
$ python manage.py badgify_sync counts --exclude-badges php
# Denormalize counts for all badges, except "php" and "java"
$ python manage.py badgify_sync counts --exclude-badges "php java"
# Typical workflow for best performances
$ python manage.py badgify_sync badges
$ python manage.py badgify_sync awards --disable-signals
$ python manage.py badgify_sync counts
# WARNING: if you delete awards to start again with a fresh table
# don't forget to update Badge.users_count field. Or use this command:
$ python manage.py badgify_reset
# Typical workflow for best performances if you want to recompute awards
$ python manage.py badgify_reset
$ python manage.py badgify_sync awards --disable-signals
$ python manage.py badgify_sync counts
Takes two optional arguments:
user
: aUser
objectusername
: aUser
username
Without any argument, displays all badges. Otherwise, badges awarded by the given user.
{% load badgify_tags %}
{% badgify_badges as badges %}
{% badgify_badges username="johndoe" as badges %}
{% badgify_badges user=user as badges %}
{% for badge in badges %}
{{ badge.name }}
{% endfor %}
django-badgify provides two views:
badgify.views.BadgifyListView
: displays all badges as paginated listbadgify.views.BadgifyDetailView
: displays awarded users as paginated list for a given badge
This application does not include templates. It lets you implement templates as you like (see example project).
To include these two views, include the provided badgify.urls
:
# -*- coding: utf-8 -*-
from django.conf.urls import include, url
urlpatterns = [
# Your other includes
url(r'^badges/', include('badgify.urls')),
]
See example project for more details.
django-badgify lets you define your own model classes for Badge
and Award
models. That can be pretty useful for i18n stuff
(example: django-transmetta support),
adding custom fields, methods or properties.
Your models must inherit from badgify.models.base
model classes:
# yourapp.models
from badgify.models import base
class Badge(base.Badge):
# you own fields / logic here
class Meta(base.Badge.Meta):
abstract = False
class Award(base.Award):
# you own fields / logic here
class Meta(base.Award.Meta):
abstract = False
Then tell the application to use them in place of default ones in your settings.py
module:
# yourapp.settings
BADGIFY_BADGE_MODEL = 'yourapp.models.Badge'
BADGIFY_AWARD_MODEL = 'yourapp.models.Award'
You can altere the application behavior by defining settings in your settings.py
module.
All application settings are prefixed with BADGIFY_
.
The root path for Badge
model ImageField
.
The URL Badge
model ImageField
.
Your own django.core.files.storage
storage instance.
Number of badges to display on the badge list page.
Number of awarded users to display on the badge detail page.
Your own concrete Badge
model class as module path.
Example: yourapp.models.Badge
.
Your own concrete Award
model class as module path.
Example: yourapp.models.Award
.
Maximum number of Award
objects to create at once.
Defaults to 500
.
# Don't have pip?
$ sudo easy_install pip
# Don't already have virtualenv?
$ sudo pip install virtualenv
# Clone and install dependencies
$ git clone https://github.com/ulule/django-badgify.git
$ cd django-badgify
$ make install
# Launch tests
$ make test
# Launch example project
$ make create_fixtures
$ make serve