-
-
Save gonzaloamadio/794d4f41539132f731d49a514ba36a71 to your computer and use it in GitHub Desktop.
Ignoring migrations during Django testing (unmanaged databases, legacy databases, etc)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ## Scenario | |
| - Django application with two databases: | |
| - Legacy database with readonly access. Both Django models (models.py) and relatead migrations have "managed" set to ```False``` | |
| - ```'managed': False``` | |
| - Default database holding django specific tables (e.g. auth_user, django_content_type, etc) | |
| ## Testing Woes | |
| - For testing I want to re-create the legacy database tables. In other words, during ```python manage.py test```, tell Django to set "managed" to ```True``` | |
| - There are several excellent blog posts on how to do this *without migrations*, especially: | |
| - http://blog.birdhouse.org/2015/03/25/django-unit-tests-against-unmanaged-databases/ | |
| - However, I was still hitting errors. Comments in the blog post above led me to this gist: | |
| - https://gist.github.com/NotSqrt/5f3c76cd15e40ef62d09 | |
| ## Combining the blog post and gist above gave the following which is working! Thanks to Scot Hacker and the gist author: | |
| ```python | |
| from project.local_settings import * | |
| from django.test.runner import DiscoverRunner | |
| class DisableMigrations(object): | |
| def __contains__(self, item): | |
| return True | |
| def __getitem__(self, item): | |
| return "notmigrations" | |
| class UnManagedModelTestRunner(DiscoverRunner): | |
| ''' | |
| Test runner that automatically makes all unmanaged models in your Django | |
| project managed for the duration of the test run. | |
| Many thanks to the Caktus Group: http://bit.ly/1N8TcHW | |
| ''' | |
| def setup_test_environment(self, *args, **kwargs): | |
| from django.db.models.loading import get_models | |
| self.unmanaged_models = [m for m in get_models() if not m._meta.managed] | |
| for m in self.unmanaged_models: | |
| m._meta.managed = True | |
| super(UnManagedModelTestRunner, self).setup_test_environment(*args, **kwargs) | |
| def teardown_test_environment(self, *args, **kwargs): | |
| super(UnManagedModelTestRunner, self).teardown_test_environment(*args, **kwargs) | |
| # reset unmanaged models | |
| for m in self.unmanaged_models: | |
| m._meta.managed = False | |
| # Since we can't create a test db on the read-only host, and we | |
| # want our test dbs created with postgres rather than the default, override | |
| # some of the global db settings, only to be in effect when "test" is present | |
| # in the command line arguments: | |
| if 'test' in sys.argv or 'test_coverage' in sys.argv: # Covers regular testing and django-coverage | |
| DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2' | |
| DATABASES['default']['HOST'] = '127.0.0.1' | |
| DATABASES['default']['USER'] = 'username' | |
| DATABASES['default']['PASSWORD'] = 'secret' | |
| DATABASES['tmi']['ENGINE'] = 'django.db.backends.postgresql_psycopg2' | |
| DATABASES['tmi']['HOST'] = '127.0.0.1' | |
| DATABASES['tmi']['USER'] = 'username' | |
| DATABASES['tmi']['PASSWORD'] = 'secret' | |
| # The custom routers we're using to route certain ORM queries | |
| # to the remote host conflict with our overridden db settings. | |
| # Set DATABASE_ROUTERS to an empty list to return to the defaults | |
| # during the test run. | |
| DATABASE_ROUTERS = [] | |
| # Skip the migrations by setting "MIGRATION_MODULES" | |
| # to the DisableMigrations class defined above | |
| # | |
| MIGRATION_MODULES = DisableMigrations() | |
| # Set Django's test runner to the custom class defined above | |
| TEST_RUNNER = 'project.test_settings.UnManagedModelTestRunner' | |
| ``` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment