Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Skip migrations for a Django 1.7 test run
# If your test settings file doesn't import any other settings file
# then you can use the function directly:
def prevent_tests_migrate(db):
import django
from django.db import connections
from django.db.migrations.executor import MigrationExecutor
django.setup()
ma = MigrationExecutor(connections[db]).loader.migrated_apps
return dict(zip(ma, ['{a}.notmigrations'.format(a=a) for a in ma]))
MIGRATION_MODULES = prevent_tests_migrate('default')
# If your test settings file imports another settings file (typically
# your base settings file, then the function won't work as the settings
# won't be fully in scope by the time setup() is called. Depending on
# you settings layout you'll an error like:
# "ImproperlyConfigured: The SECRET_KEY setting must not be empty."
# or ""Apps aren't loaded yet", or "RuntimeError: populate() isn't reentrant"
#
# Instead, simply use the function in the Django shell to generate the
# dictionary and hardcode it to MIGRATION_MODULES in the test settings.
# Since Django is already set up in the shell the function can just be:
def prevent_tests_migrate(db):
from django.db import connections
from django.db.migrations.executor import MigrationExecutor
ma = MigrationExecutor(connections[db]).loader.migrated_apps
return dict(zip(ma, ['{a}.notmigrations'.format(a=a) for a in ma]))
# You'll need to manually update MIGRATION_MODULES if you add new apps
# with migrations and want them skipped as well.
#
# Also, if you suddenly come across an error like this when Django starts up:
# "Migration foo.0001_initial dependencies reference nonexistent
# parent node (u'bar', u'0001_initial')"
# then it probably means you've added an app (maybe 3rd party) that has a
# dependency on one of the apps in MIGRATION_MODULES that you've skipped
# (e.g. a dependency on the contenttypes app). To fix, simply add the new
# app to MIGRATION_MODULES.
@nealtodd

This comment has been minimized.

Copy link
Owner Author

nealtodd commented Sep 19, 2014

Pretends migrated apps aren't migrated by giving them a fake migration module (so syncdb behaviour is used instead). Mimics the old SOUTH_TESTS_MIGRATE = False behaviour in South.

MIGRATION_MODULES could be a hard-coded dictionary of known apps. This function simply does it dynamically.

This is intended for 1.7 only, pending the --keepdb flag in Django 1.8. It's also only intended for faster running of a single test, not a whole testsuite run (which, correctly, should use migrations as Andrew Goodwin intended it to).

@n1207n

This comment has been minimized.

Copy link

n1207n commented Sep 25, 2014

This is awesome. I was bogged down by the unit tests trying to run the migrations first to create a test db. It's working greatly.

Thanks!

@mpyatishev

This comment has been minimized.

Copy link

mpyatishev commented Sep 26, 2014

Thanks!

@martync

This comment has been minimized.

Copy link

martync commented Sep 29, 2014

Placing those lines in settings.py gives me
django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty.

Trying to figure this out.

@nealtodd

This comment has been minimized.

Copy link
Owner Author

nealtodd commented Oct 1, 2014

@martync - that'll probably be because you need to define SECRET_KEY before calling prevent_tests_migrate in settings.py because the django.setup() call needs it.

@NotSqrt

This comment has been minimized.

Copy link

NotSqrt commented Nov 20, 2014

The code I come up with : https://gist.github.com/NotSqrt/5f3c76cd15e40ef62d09
No strange error, because no django.setup()

@nealtodd

This comment has been minimized.

Copy link
Owner Author

nealtodd commented Nov 25, 2014

Was just adding a comment as to why using this function directly sometimes might not work (i.e. when the test settings file imports another settings file) and saw the code from @NotSqrt.

Now that's an elegant solution!

I focused too much on replicating how Django generates its default MIGRATION_MODULES, with a fake module name, rather than faking the method calls on the dictionary.

Thanks @NotSqrt, I'll adopt your approach. (Should be fine as long as none creates an app called notmigrations ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.