From the Django docs, for any ORM query made, the DB alias to use is determined by the following rules:
Using the router scheme works perfectly for ORM queries. However, when it comes to using transaction APIs (like the transaction.atomic construct), it becomes mandatory to specify the using kwarg explicitly in all of its publicly exposed APIs if a DB other than the default alias has to be chosen.
To illustrate why this is a problem, consider the following scenario:
A proposed workaround could to be to add a separate method named db_for_transaction to the routers framework which would be consulted by the transaction APIs first, before falling back to using the default DB alias.
If we can finalise on this, I could submit a PR for the same.
Can you think of places where this db_for_transaction hook would differ in any way from what db_for_write returns? That's what Django uses internally in such instances
I get that your asking for a way to avoid explicitly passing atomic(using) all over the place but I'm having a hard time figuring out in which cases a db_for_transaction
hook, which cannot be provided any contextual details like other router
methods do, can take an an advised decision without relying on contextual/global
state.
Is there a reason you can't replace your wide spread internal uses of atomic by something along these lines
def routed_atomic(savepoint=True, durable=False):
using = get_global_using()
return transaction.atomic(using, savepoint=savepoint, durable=durable)
Cheers,
Simon
--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/001a5f54-d848-4398-8712-d0a068519f1an%40googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/b85ceacd-9f3b-4880-b934-f631489fe1can%40googlegroups.com.
I'm also -1 on changing anything in Django right now.
--
You received this message because you are subscribed to a topic in the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/django-developers/clzg6MiixFc/unsubscribe.
To unsubscribe from this group and all its topics, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/6292ccbb-bc83-48d0-b08e-aa765a29ce32n%40googlegroups.com.
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/CABP%2BMjQNWQ2AK8%3DmSQKH0%3DdNnHHeV3kSrT13R--9%3DKz%3DvbfX%2Bw%40mail.gmail.com.
I would recommend running without persistent database connections (CONN_MAX_AGE = 0) and switching settings.DATABASE["default"] in a middleware at the beginning of every request. Modifying settings at runtime isn't officially supported, but this looks like the closest option to the intent you expressed.
I don't see any reason for why providing a hook seems so difficult.
A simple implementation can be: (From message-3 of this conversation):
> #settings.pyTRANSACTION_DB_SELECTOR = "path_to_some_callable"
#transaction.py
...transaction_db_selector = import_string(settings.TRANSACTION_DB_SELECTOR)def get_connection():if transaction_db_selector:using = transaction_db_selector()if using is None:using = DEFAULT_DB_ALIASreturn connections[using]
On 1 Jun 2021, at 14:35, N Aditya <gojeta...@gmail.com> wrote:All I'm looking for is a hook that the transaction APIs can call before deciding on which database to use. I don't see any reason for why providing a hook seems so difficult.
On 2 Jun 2021, at 07:49, N Aditya <gojeta...@gmail.com> wrote:Below are a few things I'd like to clarify:
- Are you referring to thread-locals as `global state/variables` in your previous message ?
- If so, why suggest something which you consider bad practise ?
- As a consequence, if using thread-locals is considered bad software engg, could you please give me a way by which I could pass on request metadata to the router layer cleanly ?
- The final recommendation you gave is something that isn't officially supported and would fail when a threaded server or a fully async request path is used.
(Even your favourite search engine might not be of much help here)
On 3 Jun 2021, at 12:03, N Aditya <gojeta...@gmail.com> wrote:1. If atomic(using=...) is the way to go and the same has been implemented for ORM queries as well, why introduce something like the routers framework in the first place ?
2. Also generally speaking, was the intention of building the routers framework only to allow routing based on models and other hints available as part of the args list
or to expose hooks that can achieve routing of DB queries based on custom logic that could either depend on the args list or not (The use-cases are plenty. It can be from some state being pushed into a KV store based on some logic that gets executed in the view etc., not just thread-local state. Also, considering thread-local state here to be globals seems completely unfair since in actuality, it is tied to the request's scope and not global for all requests).
Also, if possible, I'd like to hear opinions about the above from the authors of the routers framework as well.
Also, I believe you quoted this in your previous message:
> Indeed, you'd need something slightly smarter, but since connections are thread-local in Django, it should be manageable.
(...)