changeset 558:9a68fd3bd8a5

Creating a simple banner / ad campaign application, initially as a RFB / SG101 tie-in.
author Brian Neal <bgneal@gmail.com>
date Thu, 02 Feb 2012 18:56:48 -0600
parents 7247a406f92b
children b9a41956be23
files gpp/banners/__init__.py gpp/banners/admin.py gpp/banners/models.py gpp/banners/templatetags/__init__.py gpp/banners/templatetags/banner_tags.py gpp/settings/base.py gpp/templates/core/rfb_block.html
diffstat 5 files changed, 164 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /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 '<img src="%s" alt="%s" />' % (obj.image.url, obj.description)
+    image_tag.allow_tags = True
+
+admin.site.register(Campaign, CampaignAdmin)
+admin.site.register(Banner, BannerAdmin)
--- /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)
--- /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
--- 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',
--- /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 %}
+<center>
+<a href="http://radiofreebakersfield.com/"><img src="{% banner_url 'rfb' %}" alt="Radio Free Bakersfield" title="Radio Free Bakersfield" /></a>
+<p>Listen to <a href="http://radiofreebakersfield.com/">Radio Free Bakersfield</a> for the SG101 Pick of the Week!</p>
+</center>
+{% endblock %}