Django queryset.count() вызывает грязную транзакцию
Я получаю неожиданную ошибку в одной из моих тестовых функций (помечена @action.commit_manually):
TransactionManagementError: Transaction managed block ended with pending COMMIT/ROLLBACK
Я отследил это до этого кода:
print 'step 1, dirty = %s' % transaction.is_dirty()
query_set = Foo.objects.filter(name='leeroy')
print 'step 2, dirty = %s' % transaction.is_dirty()
n = query_set.count()
print 'step 3, dirty = %s' % transaction.is_dirty()
Выход такой:
step 1, dirty = False
step 2, dirty = False
step 3, dirty = True
Почему вызов count() помечает транзакцию как грязную?
1 ответ
Причина в том, что транзакция помечается как грязная в любом запросе в текущих версиях django (грязная означает, что транзакция соединения выполняется). Более ранние версии django не помечали транзакцию как грязную, если только не был выполнен запрос на изменение данных - но это было изменено, поскольку этот способ несколько сбивал с толку, и, что более важно, django не знает, какие запросы модифицируют данные при использовании необработанного SQL.
Вызов filter() не открывает транзакцию, так как в этот момент не выполняется запрос.
Если вы можете, используйте транзакцию.atomic - она проста в использовании и делает все правильно во всех случаях.