Django несколько баз данных - чтение из соединения "только для чтения"; Зафиксируйте транзакцию, и все последующие запросы будут использовать соединение "по умолчанию" - PullRequest
2 голосов
/ 03 августа 2020

У меня есть 2 базы данных:

# Config
DATABASES = {
    'default': {},
    'readonly': {},
}

В фоновой задаче я хотел бы извлечь данные из базы данных «только для чтения», а затем сохранить с использованием базы данных «по умолчанию»:

# Tasks
things = Thing.objects.using('readonly').all()


util.do_stuff_with_things(things)  # ideally I don't want to make `using` a required parameter of all my utilities

Я мог бы вручную указать save(using='default') для всех утилит, но их трудно выследить. Я бы предпочел зафиксировать транзакцию, а затем начать новую транзакцию с подключением по умолчанию.

То, что я пытался:

  1. set_autocommit
transaction.set_autocommit(False, using='readonly')
thing = Thing.objects.using('readonly').first()
transaction.commit(using='readonly')

transaction.set_autocommit(True, using='default')
thing.save()  # `save` still requires `using='default'`, "InternalError: cannot execute UPDATE in a read-only transaction"
втянут в atomic блок
with transaction.atomic(using='readonly'):
    thing = Thing.objects.using('readonly').first()


thing.save()  # `save` still requires `using='default'`, "InternalError: cannot execute UPDATE in a read-only transaction"
перезапись _state.db

Это работает, но мне это не нравится: (

thing = Thing.objects.using('readonly').first()

thing._state.db = 'default'

thing.save()

На данный момент я, вероятно, go с # 3 , поскольку это наименее навязчиво для используемых мною утилит. Но интересно знать, есть ли способ лучше!

1 Ответ

0 голосов
/ 04 августа 2020

Спасибо @ arakkal-abu, Маршрутизаторы баз данных - это то, что я искал

class BGTaskDatabaseRouter:
    def db_for_read(self, model, **hints):
        return 'readonly'

    def db_for_write(self, model, **hints):
        return 'default'

в моем файле настроек:

DATABASE_ROUTERS = []
if IS_BACKGROUND_TASK:
    DATABASE_ROUTERS.append('database_routers.BGTaskDatabaseRouter'
...