Archive for the ‘Clusterify’ Category.

Altering a Django project to migrate from a simple ManyToMany relation to one with extra information

There are still quite a few features which could be useful on Clusterify. One I thought could help in structuring projects is the concept of Roles: a way to let users joining a project specify which role they want to take in it.

Now, most common tasks are made amazingly easy with Django. Changing models, while probably common, seems very tricky to automate right, though (and anyway would you trust the automation logic to make the right changes?). Yet there’s dmigrations which I need to try one day.

Back to the original problem: Roles. Formerly we had a ManyToManyField in the Project model linked to the User model for users joining a project. In the background, Django creates a table to hold the relationship named after the field (projects_project_joined_users).

The way to add extra information to a relationship, in the Django ORM, is with the “through” argument to the ManyToManyField, which lets you specify a model which will hold the relationship. In this case, we’d get:

class Membership(models.Model):
    user = models.ForeignKey(User)
    project = models.ForeignKey(Project)
    role = models.CharField(max_length=120)
    approved = models.BooleanField(default=False)

and in Project we now add the field:

    members = models.ManyToManyField(User, through='Membership')

This would create a table named projects_membership. It still doesn’t hold any data, though. Now I see two ways of making this change in the DB:

  • Renaming or copying the old table holding the relationship, and ALTERing it until it looks like that new one.
  • Creating the new table (by looking at the output of sqlall) and filling it by copying over the data with a mapping of fields.

I chose the later, which seemed more straightforward (and anyway I have other manual copying operations to perform). There’s an easy way to copy over the data, the INSERT … SELECT syntax in SQL. The old table was named projects_project_joined_users, so the syntax becomes:

INSERT INTO projects_membership (user_id, project_id, role, approved)
    SELECT projects_project_joined_users.user_id, projects_project_joined_users.project_id, '', 1
    FROM projects_project_joined_users;

Running this copied over the old data, and now the code may be updated. Note that I had first created the new table by checking the output of “sqlall” and running the relevant statements (CREATE TABLE, ALTERs for foreign key constraints, and index creation).

It’s now more complicated to handle the relationship this way, though, as one can’t use add() or remove() as before. Take a look at the doc for more info on this.

Clusterify project: word cloud bookmarklet

This is a separate post, but it’s another quick project I suggested, among the first batch I wrote as I brainstormed to get a little bit of content to get Clusterify going: a bookmarklet script to display a word cloud based on all the text in a page. The utility might be limited, but it was fun to code. Here’s the source (bookmarklet code is given in a comment) and here’s a screenshot of what it looks like:

Clusterify project: Delicious tags userscript

I’m doing a few Clusterify projects, to test the site and concept at the same time. A very quick project suggested by member psytek concerned adding popular/recommended tags automatically on Delicious with a Greasemonkey script. Turns out it took me around 10 lines of code, gave me a good excuse to finally learn about XPath, and it’s quite useful. Here’s the script over at Userscripts.