Opened 2 months ago

Closed 2 months ago

Last modified 2 months ago

#35349 closed New feature (wontfix)

Transaction API does not respect the DATABASE_ROUTERS configuration

Reported by: Vitaliy Diachkov Owned by: nobody
Component: Database layer (models, ORM) Version:
Severity: Normal Keywords: transaction, db, database routers
Cc: Vitaliy Diachkov Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Sarah Boyce)

Using the transaction API from django.db.transaction module directly does not respect the DATABASE_ROUTERS configuration and it does not grab the db_for_write() database alias by default. Instead, it always falls down to django.db.utils.DEFAULT_DB_ALIAS. The expected behaviour for this case would either use db_for_write() or introduce a new db_for_transaction() method for database routers as was proposed in this discussion. The discussion itself has no resolution in a two years, so I have decided to create a dedicated issue for that.

What I mean, if that whenever in code you use:

from django.db import transaction

@transaction.atomic()
def foo(...):
     # ... do stuff ...
     transaction.commit()

The atomic(), commit() and other functions should access the write/transaction database under the hood.


Note : I am developing an application that switches the database connection on per-tenant bases. The database configurations are added to settings.DATABASES at runtime in a middleware and then, using the contextvars.ContextVar thread-local variable, I am passing the database alias to use from a middleware to my custom database router. It works fine for reading and writing data outside the transactions, but it fails when it comes to transaction. I could potentially pass the value of ContextVar as an argument to all Transaction API calls, but it still fails for the third-party libraries that are mostly calling this functions without arguments. I have patched globally django.db.transaction.DEFAULT_DB_ALIAS to a stub string-like object that resolves dynamically in a runtime to a value of ContextVar, but that solution seems to be weird and I wish I could make it through configuring DATABASE_ROUTERS.

Change History (4)

comment:1 by Vitaliy Diachkov, 2 months ago

Description: modified (diff)

comment:2 by Sarah Boyce, 2 months ago

Description: modified (diff)
Resolution: fixed
Status: newclosed
Type: BugNew feature

Hi Vitaliy, thank you for your report.

Using the transaction API from django.db.transaction module directly does not respect the DATABASE_ROUTERS configuration and it does not grab the db_for_write() database alias by default. Instead, it always falls down to django.db.utils.DEFAULT_DB_ALIAS.

Correct, this behaviour is also documentented

atomic takes a using argument which should be the name of a database. If this argument isn’t provided, Django uses the "default" database.

I am changing this from a bug to a feature request as to update the default to be db_for_write() would be a change of behaviour and so needs some thought around deprecations etc.
For cases like this, the recommended path forward is to first propose and discuss the idea/request with the community and gain consensus. To do that, please consider starting a new conversation on the Django Forum, where you'll reach a wider audience and likely get extra feedback.

I'll close the ticket for now, but if there is a community agreement to change this behaviour, you are welcome to come back to the ticket and point to the forum topic, so we can then re-open it. For more details, please see the documented guidelines for requesting features.

comment:3 by Sarah Boyce, 2 months ago

Resolution: fixedwontfix
Note: See TracTickets for help on using tickets.
Back to Top