Почему я получаю DoesNotExist для родительской модели в save_related

Я запускаю задачу celery в save_related, которая принимает идентификатор родительского объекта и выполняет запрос get для получения экземпляра для использования.

<<<Задача

celery получает form.instance.id как parent_id

ParentModel.objects.get(id=parent_id)

Проблема в том, что некоторые запросы get завершаются с ошибкой DoesNotExist. Это не имеет смысла, потому что в документации Django ясно сказано, что "Обратите внимание, что в этот момент родительский объект и его форма уже сохранены.". Также почему не происходит сбоя у других?

Я собираюсь поэкспериментировать с тем, что произойдет, если я вызову super().save_related(...) перед задачей celery, но я не думаю, что это должно быть проблемой из-за примечания выше.

Django==4.2.3

Скорее всего, проблема возникает из-за того, что задачи celery выполняются асинхронно после возврата save_related.

Когда save_related вызывает super().save_related(), он сохраняет все данные модели в базе данных. Но затем задачи celery выполняются асинхронно.

К моменту запуска задач celery транзакции базы данных из save_related уже были зафиксированы. Поэтому любые новые идентификаторы первичных ключей, созданные во время сохранения, еще не видны в задачах celery.

Чтобы исправить это, нужно передавать задачам celery не просто ID, а реальный экземпляр модели. Таким образом, они будут иметь актуальный экземпляр с правильным ID, а не будут вынуждены получать его заново.

def save_related(self, request, form, formsets, change):

  instance = form.instance 

  # save everything
  super().save_related(request, form, formsets, change)  

  # pass instance rather than just ID
  jobs = group(
    bulk_update_task.s(instance, *args) 
    for ids_chunk in chunks(ids, 128)
  )

  jobs()

@celery_app.task  
def bulk_update_task(instance, var1, var2, var3):

  # use instance rather than refetching
  parent = instance

  # rest of task

Передавая реальный объект экземпляра, задачи celery будут иметь доступ к актуальному первичному ключу без необходимости повторной выборки из базы данных.

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