#django #django-orm
Вопрос:
Не могу найти много информации об этом. Это происходит НЕ в тесте джанго. Я использую 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()
Я не понимаю этой ошибки. Я уже создал и сохранил новый объект в БД (когда я установил object.id ни к чему и сохранил это). Почему создание других объектов создает проблему для дальнейшего сохранения?
Я попытался не создавать экземпляры объектов new_dets с помощью набора форм, а вместо этого явно определить их:
new_det = Detfac(...) new_det.save()
Но опять же, любое дальнейшее сохранение после этого вызывает ошибку.
Более подробная информация:
По сути, у меня есть Entfac
модель, и Detfac
модель, к Entfac
которой есть внешний ключ . Мне нужно создать экземпляр нового Enfac
(отличный в бд), а также соответствующий новый Detfac
для нового Entfac
. Затем мне нужно изменить некоторые значения в некоторых полях как для новых, так и для старых объектов, и сохранить все это в бд.
Ответ №1:
Ах. Приведенный выше код в порядке.
Но, оказывается, сигналы могут быть плохими. Я забыл, что при сохранении 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"....")
Сам по себе тот факт, что ЭТО не было помечено как атомарное, не является проблемой. НО если одно из этих исключений вызывает исключение, я получаю транзакцию transactionmanagementerror. Я до сих пор не уверен на 100%, почему, но в документах django упоминается, что при обертывании всего представления в atomic (или любого фрагмента кода, если на то пошло), попытка/исключение внутри этого блока может привести к неожиданному результату, потому что DJango полагается на исключение, чтобы решить, следует ли фиксировать транзакцию в целом. И данные, с которыми я тестировал, фактически вызвали исключение (ошибка типа при создании объекта HistoQuantity).
Однако обертывание попытки/исключения транзакцией.атомарный менеджер работал. Догадываюсь, что это… удалил/обработал бросок, таким образом, внешний атом мог работать.