Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading initial data with Django 1.7 and data migrations

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 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) 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.

like image 385
Mickaël Avatar asked Sep 21 '14 15:09

Mickaël


People also ask

What is the difference between Makemigrations and migrate in Django?

makemigrations is responsible for packaging up your model changes into individual migration files - analogous to commits - and migrate is responsible for applying those to your database.


1 Answers

Update: See @GwynBleidD's comment below for the problems this solution can cause, and see @Rockallite's answer below for an approach that's more durable to future model changes.


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> 
like image 131
n__o Avatar answered Oct 12 '22 14:10

n__o