Замена декоратора django commit_manually с non_atomic_requests - PullRequest
2 голосов
/ 06 июня 2019

У меня есть представление Django, которое импортирует файл Excel, и если возникают исключения, я бы хотел отловить их, сообщить обо всех и откатить все сохранения. Я получаю TransactionManagementError, хотя я использовал декоратор non_atomic_requests.

  1. Поскольку я также использую декоратор login_required, я подумал, что они могут мешать друг другу. Сначала я изменил порядок, затем удалил требуемый логин. Без изменений.

  2. Я пытался отключить автоматические транзакции во всем мире. Возможно, я сделал это неправильно, но это не то решение, которое мне нужно.

  3. Я удалил ошибочную строку кода (см. Ниже), но при попытке отката возникла та же ошибка

Он работает на Python 3.7.3 с последней версией Django и использует SQLlite. Я сейчас запускаю его как юнит-тест, хотя, возможно, я злоупотребляю этим термином. Достаточно сказать, что он работает как Django TestCase.

@transaction.non_atomic_requests
@login_required(login_url='/accounts/login/?next=/finance/gl_upload/')
def gl_upload(request):
    transaction.set_autocommit(False)
    if upriv(request.user, ['admin', 'finance']) == 'admin':
        if request.method == 'POST':

... file processing here ...

                except Exception as e:
                    errs.append(format('Exception "{1}" at row {0}\n'.format(p['rownum'], e)))
                if errs:
                    transaction.rollback()
                    rows_deleted = 0
                    rows_inserted = 0
                    print(''.join('Error: {0}\n'.format(e) for e in errs))
                else:
                    transaction.commit()
                    rows_deleted = Gldata.objects.filter(item='Actual', period_gte=older, period_lte=newest).delete()
                    rows_inserted = Gldata.objects.filter(item=temp_item).update(item='Actual')
                transaction.set_autocommit(True)
                print('Deleted: {0}, inserted: {1}'.format(rows_delete, rows_inserted))
                return render(request, 'gl_upload.html', {'inserted': rows_inserted, 'removed': rows_deleted, 'errors': errs})
            else:
                return render(request, 'gl_upload.html', {'form': form})
        else:
            form = uploadForm()
            return render(request, 'gl_upload.html', {'form': form})

Я получаю TransactionManagementError на set_autocommit, указывающий, что атомарный блок активен, даже если я понял, что декоратор отключит его. Несколько лет назад я использовал старый декоратор commit_manually, который работал просто отлично.

Файл "C: \ Users \ csullivan \ responseive \ finance \ views.py", строка 25, в gl_upload transaction.set_autocommit (False) Файл "C: \ Users \ csullivan \ responseive \ env \ lib \ site-packages \ django \ db \action.py", строка 30, в set_autocommit return get_connection (using) .set_autocommit (autocommit) Файл "C: \ Users \ csullivan \ responseive \ env \ lib \ site-packages \ django \ db \ backends \ base \ base.py", строка 394, в set_autocommit self.validate_no_atomic_block () Файл "C: \ Users \ csullivan \ responseive \ env \ lib \ site-packages \ django \ db \ backends \ base \ base.py", строка 433, в validate_no_atomic_block «Это запрещено, когда активен« атомарный »блок.») django.db.transaction.TransactionManagementError: Это запрещено, когда активен «атомарный» блок.

1 Ответ

1 голос
/ 06 июня 2019

Я думаю, что atomic() менеджер декоратора / контекста обеспечивает именно то, что вам нужно - он фиксирует транзакцию, если базовый код завершается успешно, и откатывается, когда есть исключение.

Так что в вашем случае я бы просто сделал:

with atomic():
  process_xls_files()

Вам не нужно вызывать transaction.set_autocommit() и подобные низкоуровневые методы вручную, если только у вас нет особых потребностей, а "нормальная" обработка транзакцийнедостаточно.

...