Using Sqlalchemy Declarative with Django and Nose, Oh My

So it turns out there are some painful edges if you start trying to do SQLAlchemy declarative ORM classes in an existing Django app. (For example, if you're gradually replacing the Django ORM in your code with Sqlalchemy ORM). It boils down to:

  • The django testrunner (or django-nose) changes the config for database foo to database test_foo.

  • It does that well after importing all the modules to look for tests.

  • The SQLAlchemy declarative ORM pattern requires you to inherit from a Meta class. (Not to be confused with a metaclass.) And if you want to customize the database engine params, you have to create one before you can call the declarative_base factory function:

engine = create_engine(....params...)
MyMeta = declarative_base(bind=engine, name='FOO_DB_META')

class MyModel(MyMeta):
    ... model stuff here....
  • So now your django ORM is using database test_foo and your sqlalchemy ORM is still using database foo, with predictably hilarious results.

  • Once you hack your sqlalchemy setup to fix that (probably with some horrible hack to inspect django.conf.settings and/or sys.argv to guess whether you're running tests), then if the test suite finishes and you haven't closed all SQLAlchemy connections, the test runner will hang because it's trying to delete the database and can't get a lock.

To fix those, you have to find any sessions you might have opened and make sure tests that use sqlalchemy are doing this at teardown:

    foo_session.close()
    foo_session.bind.dispose()