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:
- I would need that exact same algorithm for my current site.
- 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.

You can even customize the display a bit:

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:





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:
- context_var is whatever var contains the value you want rounded (it was ‘value’ in the screenshots)
- 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.
- half can be any of the following values: whole, half, or quarter
- 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.







October 2nd, 2007 at 11:11 pm
Nice. I was looking for something similar to this.
October 10th, 2007 at 11:41 pm
[...] Everything you’ve ever thought, but never had the balls to say. « Displaying stars (with rounding) as a Django templatetag [...]
October 14th, 2007 at 3:47 am
*thumbsup*
October 24th, 2007 at 8:17 am
[...] how I used my show_stars template tag that I blogged about a few weeks ago to display the average restaurant rating. (Cheap shameless [...]
November 28th, 2007 at 5:09 am
Sorry for the very late response, I hope you have email alerts for comments…
In case anyone else stumbles upon this, I would like to suggest a better implementation for your HTML/CSS side of things. A complementary Django bit wouldn’t be too difficult to write.
http://willhardy.com.au/files/demos/stars/
Doing it this way would mean:
* information is completely separated from the style.
* there is no need to maintain a set of complicated, half filled star images
* the result is accessible (people with screen readers, text browsers, google)
* results can still be rounded, just like before, but also has to be done in Django filter.
Please leave a reply »