Ryan Kanno: The diary of an Enginerd in Hawaii

Everything you’ve ever thought, but never had the balls to say.

Tag Archive » ‘leah-culver’

Displaying stars (with rounding) as a Django templatetag

Since my last post was quite popular (by my simple blogging standards), I’ve decided to post another Django snippet that I’ve used while coding WeGoEat. (I know, I know… one of these days I’ll finish. I’ve just been really, really lazy busy.)

After reading Leah’s blog (of Pownce fame) about “rounding to the nearest half”, I was immediately struck by two sobering realities:

  1. I would need that exact same algorithm for my current site.
  2. A few years out of grad school, and I couldn’t even begin to fathom a solution. Thank you, Internet.

In any case, I figured I’d wrap my solution into a template tag that people could use/steal/copy. Here’s a generated test page that illustrates what my template tag would display.

Stars!

You can even customize the display a bit:

25 Stars!

I know, I know… I can do a lot better. ;) In any case, here’s the code snippet that I placed in a file called show_stars.py:

import math
 
from django.template import Library, Node, TemplateSyntaxError, VariableDoesNotExist, resolve_variable
from django.conf import settings
 
register = Library()
 
IMG_TEMPLATE = '<img src="%s" alt="%s"/>'
 
PATH_TO_WHOLE_STAR = IMG_TEMPLATE % (settings.MEDIA_URL + 'img/stars/star.png', "Whole Star")
PATH_TO_THREE_QUARTER_STAR = IMG_TEMPLATE % (settings.MEDIA_URL + 'img/stars/three-quarter.png', "3/4 Star")
PATH_TO_HALF_STAR = IMG_TEMPLATE % (settings.MEDIA_URL + 'img/stars/half.png', "1/2 Star")
PATH_TO_QUARTER_STAR = IMG_TEMPLATE % (settings.MEDIA_URL + 'img/stars/quarter.png', "1/4 Star")
PATH_TO_BLANK_STAR = IMG_TEMPLATE % (settings.MEDIA_URL + 'img/stars/blank.png', "Empty Star")
 
class ShowStarsNode(Node):
    """ Default rounding is to the whole unit """
    def __init__(self, context_var, total_stars, round_to):
        self.context_var = context_var
        self.total_stars = int(total_stars)
        self.round_to = round_to.lower()
 
    def render(self, context):
        try:
            stars = resolve_variable(self.context_var, context)
        except VariableDoesNotExist:
            return ''
 
        if self.round_to == "half":
            stars = round(stars*2)/2
        elif self.round_to == "quarter":
            stars = round(stars*4)/4
        else:
            stars = round(stars)
 
        fraction, integer = math.modf(stars)
        integer = int(integer)
        output = []
 
        for whole_star in range(integer):
            output.append(PATH_TO_WHOLE_STAR)
        if self.round_to == 'half' and fraction == .5:
            output.append(PATH_TO_HALF_STAR)
        elif self.round_to == 'quarter':
            if fraction == .25:
                output.append(PATH_TO_QUARTER_STAR)
            elif fraction == .5:
                output.append(PATH_TO_HALF_STAR)
            elif fraction == .75:
                output.append(PATH_TO_THREE_QUARTER_STAR)
 
        if fraction:
            integer += 1
 
        blanks = int(self.total_stars - integer)
 
        for blank_star in range(blanks):
            output.append(PATH_TO_BLANK_STAR)
 
        return "".join(output)
 
""" show_stars context_var of 5 round to half """
def do_show_stars(parser, token):
    args = token.contents.split()
    if len(args) != 7:
        raise TemplateSyntaxError('%s tag requires exactly six arguments' % args[0])
    if args[2] != 'of':
        raise TemplateSyntaxError("second argument to '%s' tag must be 'of'" % args[0])
    if args[4] != 'round':
        raise TemplateSyntaxError("fourth argument to '%s' tag must be 'round'" % args[0])
    if args[5] != 'to':
        raise TemplateSyntaxError("fourth argument to '%s' tag must be 'to'" % args[0])
    return ShowStarsNode(args[1], args[3], args[6])   
 
register.tag('show_stars', do_show_stars)

I’ve also wrapped up the star graphics I used. A big ups to the Silk Icons creator. ;) For those of you that don’t care for .zip files, here’s all the star images I used:

Blankquarterhalfthree quarterfull

To use the tag, it’ll look something like this in your templates:

{% load show_stars %}
     {% show_stars context_var of 5 round to half %}
{% endif %}

Note: You can change the following:

  1. context_var is whatever var contains the value you want rounded (it was ‘value’ in the screenshots)
  2. 5 can be any integer; this is the maximum number of stars to display. I should probably check to make sure you don’t put a number smaller than context_var, but I’ll leave that up to you. ;)
  3. half can be any of the following values: whole, half, or quarter
  4. Make sure to edit the paths to the star files in the templatetag file

And since this is on my blog, feel totally free to take/use/steal/distribute/copy/modify any code you see fit. All I ask is if you find any bugs, have any comments, or can think of ways to make my ugly code cleaner - I’d love to hear from you. :)

Enjoy!

Tagged: , , , , , , .


Powered by Wordpress. Stalk me.