Django.db.transaction.TransactionManagementError: невозможно выполнить сохранение другого объекта в модели в рамках транзакции

Не могу найти много информации об этом. Это НЕ происходит в тесте django. Я использую DATABASES = { ATOMIC_REQUESTS: True }. В методе (в созданном мной mixin), вызываемом представлением, я пытаюсь выполнить что-то вроде этого:

def process_valid(self, view):
    old_id = view.object.id
    view.object.id = None       #  need a new instance in db
    view.object.save()
    old_fac = Entfac.objects.get(id=old_id)
    new_fac = view.object
    old_dets = Detfac.objects.filter(fk_ent__id__exact = old_fac.id)

    new_formset = view.DetFormsetClass(view.request.POST, instance=view.object, save_as_new=True)
    if new_formset.is_valid():
        new_dets = new_formset.save()

    
    new_fac.fk_cancel = old_fac    # need a fk reference to initial fac in new one
    old_fac.fk_cancel = new_fac    # need a fk reference to new in old fac

    # any save() action after this crashes with TransactionManagementError
    new_fac.save()

Я не понимаю эту ошибку. Я уже создал & сохранил новый объект в db (когда я установил object.id в None & сохранил его). Почему создание других объектов может создать проблему для последующих сохранений?

Я пробовал не инстанцировать объекты new_dets с помощью Formset, а вместо этого явно определять их:

new_det = Detfac(...)
new_det.save()

Но опять же, любое последующее сохранение после этого приводит к ошибке.

Дополнительная информация:

По существу, у меня есть модель Entfac и модель Detfac, которая имеет внешний ключ к Entfac. Мне нужно создать новую модель Enfac (отдельную в db), а также соответствующую новую модель Detfac для новой модели Entfac. Затем мне нужно изменить некоторые значения в некоторых полях для обоих новых и старых объектов и сохранить все это в db.

Ах. Код выше в порядке.

Но оказалось, что сигналы могут быть плохими. Я забыл, что при сохранении Detfac, возникает сигнал, который идет в другой класс и который в зависимости от обстоятельств добавляет запись в другую таблицу (что-то вроде таблицы истории).

Поскольку этот сигнал - всего лишь одна операция. Что-то вроде этого:

@receiver(post_save, sender=Detfac)
def quantity_adjust_detfac(sender, **kwargs):
        try:
            detfac_qty = kwargs["instance"].qte
            product = kwargs["instance"].fk_produit
            if kwargs["created"]:
                initial = {# bunch of values}
                adjustment = HistoQuantity(**initial)
                adjustment.save()
            else:
        except TypeError as ex:
            logger.error(f"....")
        except AttributeError as ex:
            logger.error(f"....")

Сам по себе тот факт, что ЭТО не было помечено как атомарное, не является проблематичным. НО если одно из этих исключений вылетает, ТО я получаю ошибку управления транзакциями. Я до сих пор не уверен на 100% почему, но в документации django упоминается, что если обернуть все представление в atomic (или любой кусок кода, если на то пошло), то try/except внутри этого блока может дать неожиданный результат, потому что DJango полагается на исключение, чтобы решить, фиксировать транзакцию в целом или нет. А данные, с которыми я тестировал, действительно вызвали исключение (ошибка типа при создании объекта HistoQuantity).

Однако обертывание попытки/исключения менеджером transaction.atomic сработало. Полагая, что это... удаляет/обрабатывает бросок, таким образом, внешний atomic может работать.

Вернуться на верх