Watch your Django field defaults do not load objects if you use South

Just ran into a South migration issue.  Basically we had a field that looked like this (simplified):

class MyModel( models.Model ):
    hostname = models.CharField(
        default = random_unique_hostname,

where random_unique_hostname() was written like so (again, simplified):

def random_unique_hostname():
    test = generate_random()
        MyModel.objects.get( hostname = test )
    except MyModel.DoesNotExist, err:
        return test
        return random_unique_hostname()

the actual code is significantly more complex, but that illustrates the problem.  When you try to generate a South migration to add some *other* field to this model (i.e. a few months after you've added this default), you'll see the migration creation fail because South is calling your default (ouch) with a database that doesn't have the new field (the pre-migration DB).

The solution is to use a minimal query, rather than calling .get, use .filter().count() or use .filter().values_list('id') or any other query that doesn't map to the whole object being loaded, just to check for unique-ness.


  1. Etienne

    Etienne on 01/19/2012 8:49 p.m. #

    For this kind of query you should use '.exists()' (need Django >= 1.2).

  2. toad

    toad on 01/19/2012 9:27 p.m. #

    i thought exists can only be used on querysets. a "get" would return the actual object no?

  3. Peter Zsoldos

    Peter Zsoldos on 01/20/2012 3:33 a.m. #

    This is one of the big problems with south migrations - as a rule of thumb, one shouldn't use your models in them, exactly because South always uses the latest version of the models.

  4. Mike Fletcher

    Mike Fletcher on 01/20/2012 8:05 a.m. #

    .exists() does sound like the correct approach. These new-fangled things... sheesh, am I really now an old-and-crufty Django programmer using all the obsolete APIs (I started at 0.9.6)... so much for migrating all the projects to 1.3.

Comments are closed.


Pingbacks are closed.