Python 2.7/Django 1.5: issue with admin inlines and many to many popup forms

I usually write a post when I waste enough time struggling about an issue. Then I spend a little more time to write the solution I wish I had found earlier, which looks so obvious then. Here is one that could have spared me an hour yesterday night: I have recently started using a method in my Django model class to concatenate multiple fields into one. Then, I save the value as the name of my object, so that the administrators or managers of the site don't have to write a name for each entry they create. The computation required in my real life example is nontrivial enough to justify saving the result in a table column (as the main name field of the model.), but here is a simpler example of what it looks like:

def concat_shirt_name(self):
    return "TShirt of size %s and color %s" % (self.size, self.color)

and the model "save" method assigns the string to the name field:

def save(self, *args, **kwargs): = self.concat_shirt_name()
    super(TShirt, self).save(*args, **kwargs)

The name field is then used as a "label" on the site (We could instead concatenate the string in unicode, but my real life example required more logic than this simple example):

def __unicode__(self): 

After registering the model in the admin, creating new objects from this model works perfectly fine, even after excluding the "name" field from the form. The issue arises when adding the model as an inline of another model form, or when it is part of another model as a ManyToManyField. Whenever submitting the popup form, you'll get the following error:

TypeError: expected a character buffer object

Despite searching for this particular error on Stack Overflow and asking on #django, I didn't find a suitable solution. After some time struggling with this, it became obvious that the issue involves the string/unicode. Simply converting the string to unicode solves the problem:

def concat_shirt_name(self):
    return unicode("TShirt of size %s and color %s" % (self.size, self.color))

or more briefly:

def concat_shirt_name(self):
    return u"TShirt of size %s and color %s" % (self.size, self.color)

As it turns out, you can skip this error and fix all together by making all strings unicode by default in your module, by adding at the top:

from __future__ import unicode_literals

The initial example would work just fine without requiring a unicode conversion.

More info on Unicode in Python and Django: