Search code examples
djangodjango-fixturesdjango-1.7django-migrations

How to create per-project initial_data fixtures in Django 1.7+


Before Django 1.7 I used to define a per-project fixtures directory in the settings:

FIXTURE_DIRS = ('myproject/fixtures',)

and use that to place my initial_data.json fixture storing the default groups essential for the whole project. This has been working well for me as I could keep the design clean by separating per-project data from app-specific data.

Now with Django 1.7, initial_data fixtures have been deprecated, suggesting to include data migrations together with app's schema migrations; leaving no obvious choice for global per-project initial data.

Moreover the new migrations framework installs all legacy initial data fixtures before executing migrations for the compliant apps (including the django.contrib.auth app). This behavior causes my fixture containing default groups to fail installation, since the auth_group table is not present in the DB yet.

Any suggestions on how to (elegantly) make fixtures run after all the migrations, or at least after the auth app migrations? Or any other ideas to solve this problem? I find fixtures a great way for providing initial data and would like to have a simple and clean way of declaring them for automatic installation. The new RunPython is just too cumbersome and I consider it an overkill for most purposes; and it seems to be only available for per-app migrations.


Solution

  • If you absolutely want to use fixtures, just use RunPythonand call_command in your data migrations.

    from django.db import migrations
    from django.core.management import call_command
    
    def add_data(apps, schema_editor):
        call_command('loaddata', 'thefixture.json')
    
    def remove_data(apps, schema_editor):
        call_command('flush')
    
    
    class Migration(migrations.Migration):
    
        dependencies = [
            ('roundtable', '0001_initial'),
        ]
    
        operations = [
            migrations.RunPython(
                add_data,
                reverse_code=remove_data),
        ]
    

    However this is recommanded to load data using python code and Django ORM, as you won't have to face integrity issues.

    Source.