Posts Tagged ‘linkedin’

A generic copy/clone action for django 1.1

Saturday, May 23rd, 2009

The last couple of days I’ve been working on customizing the django 1.1 administration to handle a number of specific permission and functionality wise things. Tonight I wrote a little function that should make your life much easier in the administration. I find, when I do administrative stuff, that it’s easier to copy something existing and work on that as a base. This is also true for my customers so why not make it possible to do so in the built in administration.

The idea is to write an admin action that takes a number of objects and clone them. The action function can be defined as:

#!/usr/bin/python/

from django.db.models.fields import CharField
def clone_objects(objects):
    def clone(from_object):
        args = dict([(fld.name, getattr(from_object, fld.name))
                for fld in from_object._meta.fields
                        if fld is not from_object._meta.pk]);

        return from_object.__class__.objects.create(**args)

    if not hasattr(objects,'__iter__'):
       objects = [ objects ]

    # We always have the objects in a list now
    objs = []
    for object in objects:
        obj = clone(object)
        obj.save()
        objs.append(obj)

def action_clone(modeladmin, request, queryset):
    objs = clone_objects(queryset)
action_clone.short_description = "Copy the selected objects"

It’s not that much code. And I made the basic clone_objects function so it can also take a single object if you want to use it somewhere else. Now you can just put the action in the ModelAdmins you’ll like or enable it site-wide.

The next thing is to make it possible to recognize the objects you have just copied. The method presented below is not very elegant but it works for most cases. I do it by looking for CharFields that have a specific name, like “title” or “name”:

#!/usr/bin/python/

from django.db.models.fields import CharField
def clone_objects(objects, title_fieldnames):
    def clone(from_object, title_fieldnames):
        args = dict([(fld.name, getattr(from_object, fld.name))
                for fld in from_object._meta.fields
                        if fld is not from_object._meta.pk]);

        for field in from_object._meta.fields:
            if field.name in title_fieldnames:
                if isinstance(field, CharField):
                    args[field.name] = getattr(from_object, field.name) + " (copy) "

        return from_object.__class__.objects.create(**args)

    if not hasattr(objects,'__iter__'):
       objects = [ objects ]

    # We always have the objects in a list now
    objs = []
    for object in objects:
        obj = clone(object, title_fieldnames)
        obj.save()
        objs.append(obj)

def action_clone(modeladmin, request, queryset):
    objs = clone_objects(queryset, ("name", "title"))
action_clone.short_description = "Copy the selected objects"

So now, if you clone a object with “Look ponies” as the title, the cloned objects will have “Look ponies (copy)” as it’s title. Here are some screen shots to show it in action:

Object list
Action selection
Copied object

Another thing you could do is to create a column in the admin list pages with a copy link that would copy-and-edit the object. This should fit a normal use case where you want to edit the object and actually differentiate the new object from the old one. It should be pretty basic to write, but it includes a view function so I won’t include it here. If you need such a link on a lot of models consider using an BaseAdmin class that all your admin classes inherit from. This way to can write the view function and link function there and have it automatic on all your admins.

Now this code has a number of drawbacks, and maybe more than I have just listed here:

  • The actual clone functionality will fail if the object you’re cloning don’t have an AutoField as it’s primary key
  • The “(copy)” append functionality is very limited and you’ll properly need change the tuple manually for every model you use unless you’re very consistent with your field naming
  • The clone functionality will properly fail hard if some of the fields are unique. The method could be made more robust by adding stuff to unique fields

Levenshtein Distance

Monday, February 23rd, 2009

I wrote a little python function to calculate the Levenshtein distance for an assignment. I figured it was some time ago since I released code on my blog, so here goes. (more…)

Our company showreel

Thursday, December 4th, 2008

Our link editor

Tuesday, November 25th, 2008

It’s been planned for a while and now it’s here.. 

BitBucket rocks

Thursday, November 20th, 2008

Earlier today Jesper showed me around at BitBucket and it’s simply fantastic. Currently I have all my private source code in a subversion repository at work, but I’m changing one of the next days. I really think it’s one of the coolest web based system around.