Loading initial data with Django 1.7 and data migrations
Question: I recently switched from Django 1.6 to 1.7, and I began using migrations (I
never used South).

Before 1.7, I used to load initial data with a `fixture/initial_data.json`
file, which was loaded with the `python manage.py syncdb` command (when
creating the database).

Now, I started using migrations, and this behavior is deprecated :

> If an application uses migrations, there is no automatic loading of
> fixtures. Since migrations will be required for applications in Django 2.0,
> this behavior is considered deprecated. If you want to load initial data for
> an app, consider doing it in a data migration.
> (<https://docs.djangoproject.com/en/1.7/howto/initial-data/#automatically-
> loading-initial-data-fixtures>)

The [official
documentation](https://docs.djangoproject.com/en/1.7/topics/migrations/#data-
migrations) does not have a clear example on how to do it, so my question is :

What is the best way to import such initial data using data migrations :

  1. Write Python code with multiple calls to `mymodel.create(...)`,
  2. Use or write a Django function ([like calling `loaddata`](http://stackoverflow.com/questions/887627/programmatically-using-djangos-loaddata)) to load data from a JSON fixture file.

I prefer the second option.

I don't want to use South, as Django seems to be able to do it natively now.


Answer: Assuming you have a fixture file in `<yourapp>/fixtures/initial_data.json`

  1. Create your empty migration:

In Django 1.7:

    
        python manage.py makemigrations --empty <yourapp>
    

In Django 1.8+, you can provide a name:

    
        python manage.py makemigrations --empty <yourapp> --name load_intial_data
    

  2. Edit your migration file `<yourapp>/migrations/0002_auto_xxx.py`

2.1. Custom implementation, inspired by Django' `loaddata` (initial answer):

    
        import os
    from sys import path
    from django.core import serializers
    
    fixture_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../fixtures'))
    fixture_filename = 'initial_data.json'
    
    def load_fixture(apps, schema_editor):
        fixture_file = os.path.join(fixture_dir, fixture_filename)
    
        fixture = open(fixture_file, 'rb')
        objects = serializers.deserialize('json', fixture, ignorenonexistent=True)
        for obj in objects:
            obj.save()
        fixture.close()
    
    def unload_fixture(apps, schema_editor):
        "Brutally deleting all entries for this model..."
    
        MyModel = apps.get_model("yourapp", "ModelName")
        MyModel.objects.all().delete()
    
    class Migration(migrations.Migration):  
    
        dependencies = [
            ('yourapp', '0001_initial'),
        ]
    
        operations = [
            migrations.RunPython(load_fixture, reverse_code=unload_fixture),
        ]
    

2.2. A simpler solution for `load_fixture` (per @juliocesar's suggestion):

    
        from django.core.management import call_command
    
    fixture_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../fixtures'))
    fixture_filename = 'initial_data.json'
    
    def load_fixture(apps, schema_editor):
        fixture_file = os.path.join(fixture_dir, fixture_filename)
        call_command('loaddata', fixture_file) 
    

_Useful if you want to use a custom directory._

2.3. **Simplest:** calling `loaddata` with `app_label` will load fixtures from
the `<yourapp>`'s `fixtures` dir automatically :

    
        from django.core.management import call_command
    
    fixture = 'initial_data'
    
    def load_fixture(apps, schema_editor):
        call_command('loaddata', fixture, app_label='yourapp') 
    

_If you don't specify`app_label`, loaddata will try to load `fixture` filename
from **all** apps fixtures directories (which you probably don't want)._

  3. Run it
    
        python manage.py migrate <yourapp>
    

