Search code examples
djangodjango-migrations

Populating db with initial data in Django


I need a way to populate db with initial data (cities) for my refs. So I've tried to do it through migrations.

Not sure it's a best way, since now I've made changes in this file after migration and can't apply it again, neither can I roll it back (since operation ...populate_cities... is not reversible) and apply again.

So my questions are:

  1. is there a way to roll such a migration back (maybe manually)?
  2. is there a better way to populate db with such data?

Solution

  • You can fix the "not reversible" part by making the migration reversible. If you used RunPython operation to populate the database, you also need to create code that reverses this operation.

    An example from documentation:

    from django.db import migrations
    
    def forwards_func(apps, schema_editor):
        # We get the model from the versioned app registry;
        # if we directly import it, it'll be the wrong version
        Country = apps.get_model("myapp", "Country")
        db_alias = schema_editor.connection.alias
        Country.objects.using(db_alias).bulk_create([
            Country(name="USA", code="us"),
            Country(name="France", code="fr"),
        ])
    
    def reverse_func(apps, schema_editor):
        # forwards_func() creates two Country instances,
        # so reverse_func() should delete them.
        Country = apps.get_model("myapp", "Country")
        db_alias = schema_editor.connection.alias
        Country.objects.using(db_alias).filter(name="USA", code="us").delete()
        Country.objects.using(db_alias).filter(name="France", code="fr").delete()
    
    class Migration(migrations.Migration):
    
        dependencies = []
    
        operations = [
            migrations.RunPython(forwards_func, reverse_func),
        ]
    

    Basically, you need a reverse function, which in many cases can be simply:

    def reverse_func(apps, schema_editor):
        pass