I have this code block that executes multiple separate queries:
Model1.objects.filter(...)
Model2.objects.filter(...)
I want all queries in this block to use a specific database. One way to do it is to explicitly specify the database name for each queryset:
Model1.objects.using('replica').filter(...)
Model2.objects.using('replica').filter(...)
I was wondering what would be the best way to achieve this API instead:
with using_database('replica'):
Model1.objects.filter(...)
Model2.objects.filter(...)
All queries inside the context using_database
should be directed to the named connection, in this case ‘replica’. Ideally, the context would route to the provided database only if using=
was not explicitly provided on the queryset.
I’ve tried using connection.execute_wrapper:
# NOTE: NOT WORKING AND PROBABLY WRONG!
def use_database(connection_name: str) -> AbstractContextManager[None]:
"""Force all queries in the context to execute in the named database.
Usage:
with use_database('replica'):
# ... queries will use the provided connection
# ... unless `using` is explicitly provided.
"""
def _handler(execute, sql, params, many, context):
connection = db_connections[connection_name],
return execute(sql, params, many, {
**context,
'connection': connection,
'cursor': connection.cursor(),
})
return db_connection.execute_wrapper(_handler)
That didn’t work. I assume because the wrapper is attached to the connection, which is what we are looking to control.
Another approach would be to register a database router while inside the context, is it doable?
Would appreciate any idea.