# HG changeset patch # User Brian Neal # Date 1328230608 21600 # Node ID 9a68fd3bd8a57198c9876293bfa2157a7c38d018 # Parent 7247a406f92b0df272720b939f1439ccc578cb2d Creating a simple banner / ad campaign application, initially as a RFB / SG101 tie-in. diff -r 7247a406f92b -r 9a68fd3bd8a5 gpp/banners/admin.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/banners/admin.py Thu Feb 02 18:56:48 2012 -0600 @@ -0,0 +1,34 @@ +""" +This file contains the automatic admin site definitions for the banners models. + +""" +from django.contrib import admin + +from banners.models import Campaign, Banner + + +class BannerInline(admin.TabularInline): + model = Banner + extra = 1 + + +class CampaignAdmin(admin.ModelAdmin): + prepopulated_fields = {'slug': ['name']} + list_display = ['name', 'slug', 'creation_date'] + date_hierarchy = 'creation_date' + search_fields = ['name'] + inlines = [BannerInline] + + +class BannerAdmin(admin.ModelAdmin): + list_display = ['campaign', 'description', 'image_tag', 'creation_date'] + date_hierarchy = 'creation_date' + search_fields = ['description'] + list_filter = ['campaign'] + + def image_tag(self, obj): + return '%s' % (obj.image.url, obj.description) + image_tag.allow_tags = True + +admin.site.register(Campaign, CampaignAdmin) +admin.site.register(Banner, BannerAdmin) diff -r 7247a406f92b -r 9a68fd3bd8a5 gpp/banners/models.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/banners/models.py Thu Feb 02 18:56:48 2012 -0600 @@ -0,0 +1,60 @@ +""" +Models for the banners application. + +""" +import datetime + +from django.db import models + + +class Campaign(models.Model): + """ + A model to represent an ad or banner campaign. + + """ + name = models.CharField(max_length=128) + slug = models.SlugField() + creation_date = models.DateTimeField(blank=True) + + def __unicode__(self): + return self.name + + class Meta: + ordering = ['name'] + + def save(self, *args, **kwargs): + if not self.pk and not self.creation_date: + self.creation_date = datetime.datetime.now() + + super(Campaign, self).save(*args, **kwargs) + + +def banner_upload_to(instance, filename): + """ + An "upload_to" function for the Banner model. + + """ + return "banners/%s/%s" % (instance.campaign.slug, filename) + + +class Banner(models.Model): + """ + A model to represent a banner. + + """ + campaign = models.ForeignKey(Campaign) + image = models.ImageField(upload_to=banner_upload_to) + description = models.CharField(max_length=128) + creation_date = models.DateTimeField(blank=True) + + def __unicode__(self): + return self.description + + class Meta: + ordering = ['-creation_date'] + + def save(self, *args, **kwargs): + if not self.pk and not self.creation_date: + self.creation_date = datetime.datetime.now() + + super(Banner, self).save(*args, **kwargs) diff -r 7247a406f92b -r 9a68fd3bd8a5 gpp/banners/templatetags/banner_tags.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/banners/templatetags/banner_tags.py Thu Feb 02 18:56:48 2012 -0600 @@ -0,0 +1,60 @@ +""" +Template tags for the banners application. + +""" +import logging + +from django import template +import redis + +from core.services import get_redis_connection +from banners.models import Banner + + +register = template.Library() +logger = logging.getLogger(__name__) + +BANNER_URL_KEY = 'banners:url:%s' + + +@register.simple_tag +def banner_url(slug): + """ + Returns the URL for the next banner in the campaign whose slug is 'slug'. + + For each campaign, a list of banner URLs are kept in Redis. Each time this + tag is called, the front banner is popped off the list. When the list is + empty, we refresh the list from the database. In this way the banners for a + campaign are cycled through. + """ + key = BANNER_URL_KEY % slug + + try: + conn = get_redis_connection() + url = conn.lpop(key) + except redis.RedisError, e: + logger.error("banner_url: '%s' on lpop", e) + return u'' + + if url: + return url + + # list not found or empty, rebuild it from the database + + qs = Banner.objects.filter(campaign__slug=slug) + urls = [banner.image.url for banner in qs] + if not urls: + logger.warning("banner_url: no banners for campaign '%s'", slug) + return u'' + + url = urls[0] + urls = urls[1:] + + if urls: + try: + conn.rpush(key, *urls) + except redis.RedisError: + logger.error("banner_url: '%s' on rpush", e) + pass + + return url diff -r 7247a406f92b -r 9a68fd3bd8a5 gpp/settings/base.py --- a/gpp/settings/base.py Sun Jan 29 14:45:09 2012 -0600 +++ b/gpp/settings/base.py Thu Feb 02 18:56:48 2012 -0600 @@ -121,6 +121,7 @@ 'tagging', 'accounts', 'antispam', + 'banners', 'bio', 'bulletins', 'comments', diff -r 7247a406f92b -r 9a68fd3bd8a5 gpp/templates/core/rfb_block.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/templates/core/rfb_block.html Thu Feb 02 18:56:48 2012 -0600 @@ -0,0 +1,9 @@ +{% extends 'side_block.html' %} +{% load banner_tags %} +{% block block_title %}R.F.B.{% endblock %} +{% block block_content %} +
+Radio Free Bakersfield +

Listen to Radio Free Bakersfield for the SG101 Pick of the Week!

+
+{% endblock %}