8
votes

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.

2
Since it's deprecated it's probably gonna be a bit awkward. One option might be to create a minimal app for loading the initial data only, create a migration, and in RunPython, call whatever functions Django uses for loading fixtures. That way you could also specify dependencies in your migration. It would probably involve some serious digging in the Django source code though.Joar Leth
Yeah, I've though about creating some kind of meta application as a last resort and creating the migrations there (but it's still ugly). Wonder why the new Django does not at least provide a standard way of declaratively specifying fixtures to be loaded together with the new Migrations.knaperek
Somewhere on SO it was suggested to reuse the pre-1.7 json/xml fixture files. You would have a minimal app with just a data migration, then parse your existent json/xml fixtures and create records from them. This should be what happened pre-1.7 anyways.user1415946

2 Answers

4
votes

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.

1
votes

I recommend using factories instead of fixtures, they are a mess and difficult to maintain, better to use FactoryBoy with Django.