Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to override database settings in Django tests?

I'm on Django 1.8 (using pytest) and I have the following configuration:

  • A default and a readonly database managed by a MasterSlaveRouter that directs DB calls to one connection or the other depending on whether they're read or write operations.
  • In my development environment, both entries in the settings.DATABASES dictionary have the same setup (they just use a different connection, but the database is the same).
  • In my test environment, however, there's only a default database.
  • I have a post_save signal fired whenever a model Foo is saved.
  • I have an atomic operation (decorated with @transaction.atomic) that modifies a Foo instance and calls .save() on it twice. Since no custom using parameter is passed to the decorator, the transaction is only active on the default database.

The post_save callback creates a Bar record with a OneToOneField pointing to Foo, but only after checking whether a Bar record with this foo_id already exists (in order to avoid IntegrityError). This check is done by performing this query:

already_exists = Bar.filter(foo=instance).exists()

This is ok the first time the post_save callback is called. A Bar record is created and everything works fine. The second time, however, even though such a Bar instance was just created in the previous Foo save, since filtering is a read operation, it is performed using the readonly connection, and therefore already_exists ends up containing the value False and the creation of a new record is triggered, which eventually throws an IntegrityError because when the create operation is performed on the default connection, there is already a record with that foo_id.

I tried copying the DATABASES dictionary from dev_settings to test_settings, but this broke many tests. I then read about the override_settings decorator and thought it would be perfect for my situation. For my surprise, however, it didn't work. It seems that at some point, when the application is initiated, the DATABASES dictionary (the one only with default from the test_settings) is cached and then even though I change setting.DATABASES, the new value is simply not accessed anymore.

How can I properly override the database configuration for one specific test?

like image 626
Ariel Avatar asked Oct 25 '25 20:10

Ariel


1 Answers

Hum... well if you are using only pytest, I think you'll need to cleanup your databases after tests.

Now, to override django settings, it's good to :

from django.test import override_settings
@override_settings(DATABASE_CONFIG=<new_config>)
def test_foo():
    pass

You should try the pytest-django:

pytestmark = pytest.mark.django_db

@pytest.mark.django_db
def test_foo():
    pass

When you run your tests, you can set the create-db param, to force py.test create a new database or if you want to reuse your db, you can set the reuse-db, like:

$ py.test --create-db
$ py.test --reuse-db

checkout: Oficial docs

like image 144
Ederson Badeca Avatar answered Oct 27 '25 11:10

Ederson Badeca



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!