Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save gonzaloamadio/794d4f41539132f731d49a514ba36a71 to your computer and use it in GitHub Desktop.

Select an option

Save gonzaloamadio/794d4f41539132f731d49a514ba36a71 to your computer and use it in GitHub Desktop.
Ignoring migrations during Django testing (unmanaged databases, legacy databases, etc)
## 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