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.