2012-09-27

Initial Data Using South Migrations

Usually when starting a new project with commonly used apps, you will need some default data for the database, for example, default categories. Django provides fixtures for that. A fixture is a collection of data that Django knows how to import into a database.

They say:

If you create a fixture named initial_data.[xml/yaml/json], that fixture will be loaded every time you run syncdb.

There is one problem with this approach. It is very likely that you will need to run syncdb in the future when adding new apps (without south migrations). In such cases the modified data will be overwritten with the initial data from fixtures.

But there is a solution for that problem. You need to name your fixtures differently and then import them by south migrations. If you don't use south, you should start doing that, because it is a very handy way to modify database schema and data automatically. :)

So this is how you can prepare south migration with the default fixture:

1. Create a fixture from existing models.

python manage.py dumpdata --format=json --indent=4 myapp.Category > /path/to/myapp/fixtures/myapp_categories.json

2. Create data migration

python manage.py datamigration myapp load_default_data

3. Edit data migration

class Migration(DataMigration):
    
    def forwards(self, orm):
        from django.core.management import call_command
        call_command("loaddata", "myapp_categories.json")
    
    def backwards(self, orm):
        pass

4. Migrate

python manage.py migrate myapp

2 comments:

  1. Thanks for the idea. I tried it and seemed to work, except when deploying elsewhere. Because the db is created fresh, it doesn't run old migrations, they are faked. So these data migrations don't get run and the tables are empty. Did you end up with a solution to this?

    ReplyDelete
  2. This won't work well. loaddata uses normal Django models, meaning if you add new columns later, reset database, run this loaddata-migration, it will fail as it will load Django's models with the newest columns, while database is in an old state without those.

    ReplyDelete