views:

285

answers:

1

I will be frequently running testcases for my django project. But one fine day it occured to me that django actually checks the settings.DATABASE_NAME db actual existence while running testcases. Why is this so. All I thought was django will be taking the settings.DATABASE_NAME and creates a test db called 'test_' + settings.DATABASE_NAME. It also checks whether the database with the name = settings.DATABASE_NAME, is actually existing or not(for creating the test db)? Ideally speaking, only name should be checked but not the actual existence of the db right?

I browsed through the django source code and found out that the "connection" which is used to create the testdb actually is created using DATABASE setting options. All it should be bothered about settings' values and not their actual existence. Right?

+2  A: 

Neat question... you know, this had never occurred to me. The short answer is that Django itself doesn't need to verify that the DATABASE_NAME actually exists, but it does need to connect to the database in order to create the test database. Most databases accept (and some require) the DATABASE_NAME in order to formulate the connection string; often this is because the database name to which you're connecting contributes to the permissions for your connection session.

Because the test database doesn't exist yet, django has to first connect using the normal settings.DATABASE_NAME in order to create the test database.

So, it works like this:

  • Django's test runner passes off to the backend-specific database handler
  • The backend-specific database handler has a function called create_test_db which will use the normal settings to connect to the database. It does this using a plain cursor = self.connection.cursor() command, which obviously uses the normal settings values because that's all it knows to be in existence at this point.
  • Once connected to the database, the backend-specific handler will issue a CREATE DATABASE command with the name of the new test database.
  • The backend-specific handler closes the connection, then returns to the test runner, which swaps the normal settings.DATABASE_NAME for the test_database_name
  • The test will then run as normal. All subsequent calls to connection.cursor() will use the normal settings module, but now that module has the swapped out database name
  • At the end, the test runner restores the old database name after calling the backend-specific handler's destroy_test_db function.

If you're interested, the relevant code for the main part is in django.db.backends.creation. Have a look at the _create_test_db function.

I suppose that it would be possible for the Django designers to make exceptions on a db-by-db basis since not every DB needs the current database name in the connection string, but that would require a bit of refactoring. Right now, the create_test_db function is actually in one of the backend base classes, and most actual backend handlers don't override it, so there's be a fair amount of code to push downstream and to duplicate in each backend.

Jarret Hardie
Awesome Jarret! Thankyou
Maddy
+1 for digging into the source.
Carl Meyer