Posted on May 27, 2008 at 2:47 A.M.

Recently I've been using a lot of FriendFeed lately, and found it a bit annoying to expand comments one-by-one, so I wrote a quick bookmarklet to automatically expand all comments out.

Drag this bookmarklet to your bookmarks toolbar to get in on the action:

Show All Comments

By the way, feel free to follow me on FriendFeed as well to see my various online activities. I'm in the habit of following people who follow me.


Posted on Jan. 30, 2008 at 12:02 P.M.

It's an interesting feeling open-sourcing an application that you've developed for your own purposes. Will people use it? Will people find major design flaws? Is it just a big waste of time? These were the questions that were going through my mind before open-sourcing django-threadedcomments. Fortunately, my worries were quelled almost instantly as a people reacted quite positively to the application. There was one recurring comment, however, that almost everyone who tried the sample implementation said: those colors are hideous.

Beyond even that though, it seems that people saw the sample implementation and got the impression that django-threadedcomments = that sample implementation. To me, that's an underestimation of the power of the modular django app. I think that James Bennett hits the nail on the head when he says that:

"Rather than a single definitive 'Django blog' application, for example, I think it’s much more likely we’ll see a collection of applications which, taken together, provide all the key functionality..."

It was this sentiment that pervaded nearly all of the design decisions behind django-threadedcomments: it should be flexible, modular, and reusable so that, taken together with other similarly-designed apps, it can provide some compelling functionality at a fraction of the effort. Now we most assuredly didn't achieve all of those design goals fully, but I believe we're headed in at least the right direction with its development.

To prove my point, I decided to create an improved Digg/Reddit comment system clone using Jonathan Buchanan's wonderful django-voting application, alongside django-threadedcomments, and a fair bit of jQuery. Being almost completely new to Javascript, I was pleasantly surprised by how easy it was to not only integrate all of these technologies and use extensive client- and server-side scripting, but also to achieve a compelling commenting system in well under a week of spare time. Oh, and this time there was actually some effort in making the look and feel of the commenting system acceptable! As with the first example, this one is completely open sourced and available in the django-threadedcomments SVN repository.

Without further ado, the Example Digg/Reddit Comment Clone Plus Focus.



Posted on Dec. 18, 2007 at 12:37 P.M.

Widgets are everywhere! It seems that every blog these days has at least a couple of widgets on their sidebar. Yesterday I realized that I had never written one, and probably more importantly, I really had no concrete idea how they worked. Using Django and a bit of Javascript, it turned out to be quite easy! I'm going to show you the basics of how to write a widget yourself, but if enough people would like the source code to mine, I'll happily open source it.

Before starting on creating a widget, we've got to make sure that it has an API of some sort. In the case of Pownce, there some Community Documentation about the various things that can be done with its API. For a simple widget, all we really need is to be able to fetch some public notes.

Our API call will be: http://api.pownce.com/1.1/public_note_lists.json

Now that we've determined where to get our data, let's parse it and do something with it.

from urllib2 import urlopen
from django.utils import simplejson
from django.template import loader, Context
from django.http import HttpResponse
def pownce_widget(request):
    api_call = "http://api.pownce.com/1.1/public_note_lists.json"
    notes = simplejson.loads(urlopen(api_call).read())['notes']
    t = loader.get_template('powncewidget/widget_content.html')
    c = Context({'notes' : notes})
    return HttpResponse(t.render(c))

Now you may be noticing that I'm not using the simpler django.shortcuts.render_to_response. That's because we're going to use the content that we've rendered here as context for another template which we'll use in a moment. Also note that if you were to do this in a production environment, using a simple urlopen is not considered good practice. See chapter 11 in Mark Pilgrim's excellent Dive Into Python for more information about what to do instead.

Now let's create a template:

<ul id="pownce_widget">
    {% for note in notes %}
        <li><a href="{{ note.permalink }}">{{ note.body|slice:":30" }}</a></li>
    {% endfor %}
</ul>

What we've done here is iterated over the public notes, and simply created an unordered list with the first 30 or less words from the note. Also, we've provided a link to Pownce for each note listed.

If browsers could make cross-domain requests, we'd be done now: you could embed a small Javascript file which would asynchronously request this page and update the DOM accordingly. However, this is not possible, so I've come up with a way to do it instead. I'm not sure if it's a best practice--it sure seems to me like it's not--but it works, which is probably more important anyway.

So let's modify our view:

from urllib2 import urlopen
from django.utils import simplejson
from django.template import loader, Context, RequestContext
from django.http import HttpResponse
from django.shortcuts import render_to_response
def pownce_widget(request):
    api_call = "http://api.pownce.com/1.1/public_note_lists"
    notes = simplejson.loads(urlopen(api_call).read())['notes']
    t = loader.get_template('powncewidget/widget_content.html')
    c = Context({'notes' : notes})
    context = {"widget_content" : t.render(c))}
    return render_to_response("powncewidget/widget.html", context, context_instance=RequestContext(request))

We've taken the rendered output from widget_content.html and used it as context for another template, widget.html, which we return as an HttpResponse to the browser. This doesn't make much sense until we've seen what that widget.html template contains. Here it is:

{% load stripwhitespace %}

var _cssNode = document.createElement('link');
_cssNode.type = 'text/css';
_cssNode.rel = 'stylesheet';
_cssNode.href = '{{ MEDIA_URL }}css/powncewidgetstyle.css';
_cssNode.media = 'screen';
document.getElementsByTagName("head")[0].appendChild(cssNode);
document.write('{{ widget_content|stripwhitespace|safe }}');

What we're doing here is dynamically creating Javascript using Django's templating system which injects your rendered HTML into the page. The first few lines add a new stylesheet to the page, and the last one writes your content to the page. But what is this stripwhitespace filter that we see? Javascript does not like multi-line string declarations such as what widget_content produces. With Django, it's easy to write a simple filter to make it all exist on one line:

from django import template
import re
inbetween = re.compile('>[ \r\n]+<')
newlines = re.compile('\r|\n')
register = template.Library()
def stripwhitespace(value):
    return newlines.sub('', inbetween.sub('><', value))
register.filter('stripwhitespace', stripwhitespace)

With that, we've pretty much finished up on creating our widget. There are lots of customization options from here: GET arguments, different API endpoints, etc. Not only that, but there's lots of room for visual customization using CSS. What we're doing is effectively generating Javascript, so anything that you'd like to do using Javascript is fair game as well.

The result after tweaking for a bit is what you see at the right under my "Widgets" links. Here is a picture in case it stops working for some reason:

http://media.eflorenzano.com/img/powncesample.png

If you'd like to create a pownce widget of your own by simply adding a snippet to your site, I've provided a Pownce Widget Creator for your convenience.

I think that it was fairly easy to do this using Django and Python, and if you've got any tips on best practices, please let me know so that I can code a better widget!

Search

 

Recent Links

  • git-issues: A distributed issue tracker built-in to Git.
  • I predicted this back in March--can't believe a solution has surfaced so soon. It makes so much sense to build in an issue tracker to a revision control system. Since you're working with the code, might as well track the issues in the same system and take advantage of the extra metadata. This is really cool (and as a bonus, it's written in Python) so I hope to see it really grow and flourish!

  • How I Work Daily
  • Daily blog by Kevin Fricovsky. In addition to having some really great content, he has started to post audio interviews with people from the Django community. This is a site to keep an eye on in the coming days and months.

  • django-arcade
  • Demo site for django-arcade, an open source reusable Django app to add new flash games to any django-powered site. Looks very cool for easily creating game portals. It also comes from my future employer.

  • Facebook Chat and Scalability (with Erlang)
  • Eugene Letuchy talks about how they they took Facebook Chat from no users to 70 million users, with the help of Erlang.

  • Simon Willison: The Implications of OpenID
  • I somehow missed this presentation when it came out, but it's an absolutely fantastic overview and defense of OpenID by Simon Willison. If you are in any way interested in what OpenID is and what it can offer, you owe it to yourself to check out this presentation.

  • StupidXML
  • Probably the simplest XML library that I've seen for Python. Sometimes you just want to generate some stupid XML, and this is the perfect tool for the job.

  • See the rest of my links...

Pownce

Badges

  • django badge
  • apache badge
  • GeoURL
  • XFN Friendly
  • Valid HTML 4.01 Transitional