Archive for the 'Python' Category

Django localized date template filter

Friday, July 10th, 2009

UPDATE! This is going to be redundant in Django 1.2, in which you can add DATE_FORMAT to your django.po files.

I’ve often been frustrated that using settings.DATE_FORMAT does not give a localized date. Granted that the name of a month may be localized, but the format string does not change. So let’s start out by modifying settings.py. We wrap our default date format in a ugettext so the makemessages command will detect it, and we need to make it a dummy function, because the i18n library cannot be imported in settings.py due to circularity (it depends on settings.py).

ugettext = lambda s: s
DATE_FORMAT = ugettext('N j, Y')

Run compilemessages and type in your localized date formats. Now we need a template filter that uses a localized format for calling the Django date format function. This is really simple:

from django.template.defaultfilters import stringfilter
from django.utils import dateformat
from django.utils.translation import ugettext
from django.conf import settings
 
@register.filter()
def localdate(value):
    """Format date with localized date format"""
    format = ugettext(settings.DATE_FORMAT)
    return dateformat.format(value, format)

And done. Using the filter is straight forward:


Date: {{ my_date|localdate }}

Presenting: django-simple-wiki

Monday, April 27th, 2009

It was bothering me that all the wikis I tried, all had either errors, feature lacks, too many dependencies or were simply unmaintained. So I decided to create yet another one. Curiously, the third hit when googling ‘django wiki’ is Create a wiki in 20 minutes. Luckily that’s not really true, so all the PHP guys and MediaWiki can continue breathing. This took me several days.

Google Code project page

Demo website

Hierarchy and relations
First of all, as in the Trac wiki system, I chose to create a system for hierarchy, meaning that it’s possible to create an article and then create sub-articles. The hierarchy does not support multiple inheritance, because it needs to be basis for the permission system. That’s where the relation system comes in place: All articles can contain symmetrical relations to any other articles in the hierarchy.

Parsing
Python and Django supports Markdown pretty much out of the box, so it’s an obvious choice to use this for parsing. The HTML features of normal Markdown have been removed, so all HTML is escaped in django-simple-wiki. And parsing is static, so every time a revision is created, the contents are passed and stored. This means that the contents of the article itself are not supposed to be dynamic. On the other hand, it is desirable to avoid parsing contents for every page hit. The parsing area of the application is only a few lines of code, and can be expanded if further parsing needs to be done, or someone wants to replace Markdown completely. For instance, if no parsing is done and HTML escaping is disabled, the wiki becomes a very simple CMS.

Curious issues
There are a few out standing problems:

  • Permission system is related to User entries in the Django auth system. But maybe this is too much of an annoyance, if the project already has groups setup in the existing auth system. On the other hand, other users would be bothered to setup both wiki groups and user groups, if the permission system was linked to user groups. And directly linking articles to user groups would require wiki-related groups to be created directly in the auth system.
  • Since relations are symmetrical, what should happen if one article is locked, but a user modifies it’s relations by deleting them from related articles?
  • Title editing: The title can only be created once, since it is coupled to the ’slug’ of the article. A user can deliberately create a completely different title, which is fine, but should subsequent editing be allowed, which would add complexity to the revision system?
  • Article deletion: When an article is deleted from the backend it shouldn’t worry anyone. But if the feature is added to the frontend, we would want to handle maliciousness etc. But should we really store all these files and revisions? Should we alert admins, so they can do the final cleanup?

GTK and scrolling without scrollbars

Tuesday, January 27th, 2009

There’s still some work to do on the full screen plugin for Rhythmbox, but the current version is very usable indeed. The latest addition is scrolling by hovering the track list.

I changed the display from a normal fixed table with 3 tracks to a gtk.Layout with a gtk.VBox containing n tracks. In a Layout widget it’s possible to freely place and move child widgets, so by detecting motion events on the edges of the Layout you can emulate scrolling by moving a child widget accordingly with Layout.move(widget, x, y). Unfortunately I get a rather nasty blinking effect when scrolling too fast, and I don’t have an explanation for this, so I’d be glad to hear from anyone who can help.

def track_layout_scroll(self, widget, event):
    time_step = 10 #msecs
    ycoord = event.y
    accel_factor = 10 #how many pixels to scroll at the edge
    edge_distance = 100.0 #pixels
    layout_size = widget.get_size()
    top_dist = edge_distance - ycoord
    bot_dist = edge_distance - layout_size[1] + ycoord
 
    if top_dist > 0:
        accel = -1 - (top_dist / edge_distance) * accel_factor
    elif bot_dist > 0:
        accel =  1 + (bot_dist / edge_distance) * accel_factor
    else:
        accel = 0.0
 
    if self.scroll_event_id:
        gobject.source_remove(self.scroll_event_id)
 
    if not accel == 0.0:
        self.scroll_event_id = gobject.timeout_add(time_step, self.do_scrolling, accel, widget)
 
def do_scrolling(self, accel, layout_widget):
    step = int(1*accel)
    if step == 0:
        return
    vbox_size = self.vbox.size_request()
    layout_size = layout_widget.get_size()
    scroll_height = vbox_size[1]-layout_size[1]
    if self.scroll_y + step < 0:
        self.scroll_y = 0
    elif self.scroll_y + step > scroll_height:
        self.scroll_y = scroll_height
    else:
        self.scroll_y += step
 
    self.track_layout.move(self.vbox, 0, -self.scroll_y)
    return self.scroll_y > 0 and self.scroll_y < scroll_height

The code is related to my Rhythmbox plugin, but I’m sure you get the idea. Also please note, that track_layout_scroll has to receive notify_motion_event from the Layout widget, and that you have to set a size for the Layout widget with set_size().

Update: By playing around with time_step (lowering it to be more exact) and slowing down the acceleration, I managed to almost make the white flashes disappear.