Opened 6 years ago

Closed 6 years ago

Last modified 2 years ago

#29801 closed New feature (duplicate)

Allow using fixtures in data migrations

Reported by: Calvin DeBoer Owned by: nobody
Component: Migrations Version: dev
Severity: Normal Keywords: environments migrations
Cc: Alex Dehnert Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Calvin DeBoer)


Django's current recommendation for adding data to a application is through the well documented "DataMigration" via RunSQL and RunPython calls. This represents an improvement over the fixture loading for a variety of reasons (it doesn't force developers to keep their fixtures up to date, control over overwriting data ,etc). Fixtures would be great if they didn't have to be kept up to date with the DB's current state (more on that later). As the applications we've been building with Django have grown in complexity we've seen an increase in the need to have control over which data is created in different application environments. For example, in production we want to add a large dataset foo (production data), but in development we only want to load a smaller dataset bar (for Developer Experience); furthermore, in tests we don't want to add ANY data because we want the tests, setUp method to granularly control what data is available in the DB with that set of tests. For the test piece, we investigated setting the MIGRATION_MODULES setting to None for all the apps in a test_settings file, but that seemed heavy handed, and also only handled a single application environment.


  1. add a method called loaddata that takes a fixture and apps <- (the model context within a migration from which one can obtain a FakeModel instance representing the Model at state of that migration.
import os
from django.db import migrations
import environize

PATH = 'path/to/fixtures/'

def load_fixture(apps, schema_editor):
    fixture_file = os.path.join(PATH, 'myfixture.json')
    environize.loaddata(apps, fixture_file)

class Migration(migrations.Migration):

    dependencies = [
        ('app', '0003_auto_20180916_1122'),

    operations = [
        migrations.RunPython(load_fixture, lambda x, y: None)

  1. allow RunPython and RunSQL to take an additional keyword that will tell django which envs to include or exclude in a DataMigration.
class Migration(migrations.Migration):

    dependencies = [
        ('app', '0002_auto_20180916_1122'),

    operations = [
        migrations.RunPython(add_prod_data, remove_hams, only_in=['production']),
        migrations.RunSQL("INSERT blah;", "REMOVE blah;", except_in=['test'])


Here is a hastily put together library to allow environments inside migrations and have state specific loaddata . The environment stuff is implemented as decorators on the function at the moment, probably makes more sense to just inherit RunPython and RunSQL and provide the keywords shows above in example 2.

Probably makes the most sense to continue to develop this as a package outside of Django, but before I do that, thought I'd see if there is any appetite for it in core django.

Change History (5)

comment:1 by Calvin DeBoer, 6 years ago

Description: modified (diff)

comment:2 by Tim Graham, 6 years ago

Resolution: duplicate
Status: newclosed
Summary: Feature Suggestion for MigrationsAllow using fixtures in data migrations

Duplicate of #24778.

comment:3 by Calvin DeBoer, 6 years ago

Is there another ticket to reference for the bit in the description about excluding certain environments for various DataMigration operations ? The duplicate ticket was just for loading fixture data in migrations.

comment:4 by Tim Graham, 6 years ago

Sorry, I don't need that far. I'm not immediately convinced something like that is needed as I think you should be able to whatever Python conditions you like to conditionally add operations to Migration.operations.

comment:5 by Alex Dehnert, 2 years ago

Cc: Alex Dehnert added
Note: See TracTickets for help on using tickets.
Back to Top