EDIT:
These other answers make more sense:
ORIGINAL:
Running your data-migration functions (such as combine_names
from the OP's example) through some basic unit-tests, before actually applying them, makes sense to me too.
At first glance this should not be much more difficult than your normal Django unit-tests: migrations are Python modules and the migrations/
folder is a package, so it is possible to import things from them. However, it took some time to get this working.
The first difficulty arises due to the fact that the default migration file names start with a number. For example, suppose the code from the OP's (i.e. Django's) data-migration example sits in 0002_my_data_migration.py
, then it is tempting to use
from yourappname.migrations.0002_my_data_migration import combine_names
but that would raise a SyntaxError
because the module name starts with a number (0
).
There are at least two ways to make this work:
Rename the migration file so it does not start with a number. This should be perfectly fine according to the docs: "Django just cares that each migration has a different name." Then you can just use import
as above.
If you want to stick to the default numbered migration file names, you can use Python's import_module
(see docs and this SO question).
The second difficulty arises from the fact that your data-migration functions are designed to be passed into RunPython
(docs), so they expect two input arguments by default: apps
and schema_editor
. To see where these come from, you can inspect the source.
Now, I'm not sure this works for every case (please, anyone, comment if you can clarify), but for our case, it was sufficient to import apps
from django.apps and get the schema_editor
from the active database connection
(django.db.connection).
The following is a stripped-down example showing how you can implement this for the OP example, assuming the migration file is called 0002_my_data_migration.py
:
from importlib import import_module
from django.test import TestCase
from django.apps import apps
from django.db import connection
from yourappname.models import Person
# Our filename starts with a number, so we use import_module
data_migration = import_module('yourappname.migrations.0002_my_data_migration')
class DataMigrationTests(TestCase):
def __init__(self, *args, **kwargs):
super(DataMigrationTests, self).__init__(*args, **kwargs)
# Some test values
self.first_name = 'John'
self.last_name = 'Doe'
def test_combine_names(self):
# Create a dummy Person
Person.objects.create(first_name=self.first_name,
last_name=self.last_name,
name=None)
# Run the data migration function
data_migration.combine_names(apps, connection.schema_editor())
# Test the result
person = Person.objects.get(id=1)
self.assertEqual('{} {}'.format(self.first_name, self.last_name), person.name)