см. update
Ошибка возникает при обработке сигнала pre_save. В тесте test_article_sorting() создается объект статьи, перед сохранением в бд посылается сигнал pre_save и выполняется функция delete_old_article_image, где в строчке
article = Article.objects.get(pk=instance.pk)
.get() метод пытается получить несуществующий объект статьи из бд и после этого рэйсит ошибку DoesNotExist
Одно из нескольких возможных решений - обернуть в блок try/except:
@receiver(pre_save, sender=Article)
def delete_old_article_image(sender, instance, *args, **kwargs):
if instance.pk:
try:
article = Article.objects.get(pk=instance.pk)
if instance.image and article.image != instance.image:
slide.image.delete(False)
except Article.DoesNotExist:
pass
Ну и естественно все это тоже надо покрыть тестами, тут их будет как минимум 3.
UPDATE:
Сегодня что-то вспомнил этот вопрос, еще раз открыл, понял почему на "продакшене" работало, а в тестах нет:
Как я уже говорил, в тестах, ты создаешь объекты статьи с помощью шортката .create() который внутри себя создает объект obj с указанными тобою параметрами и вызывает save() для его сохранения в базу данных, отправляется сигнал pre_save, в хэндлер передается твой объект с имеющимся pk, выполняется твой код, условие
if instance.pk срабатывает и начинается попытка получить несуществующий объект из базы, что оканчивается ошибкой.
Почему работало на живом сайте? Вот почему:
На "живом" сайте, когда ты создаешь новый объект, при его сохранении в хэндлер сигнала pre_save() передается instance с pk == None, так как primary key вешается самой базой данных после всех джанговских штучек, поэтому на этом этапе if instance.pk возвращало False и вложенный код не выполнялся.
Когда же ты редактировал уже существующий объект при сохранении в хэндлер pre_save() передавался "уже имеющийся" в базе объект у которого есть pk и у которого, возможно, теперь слегка измененные данные (раз уж редактируем то что-то да меняем) что приводило к выполнению условия if instance.pk и выполнению вложенного кода который успешно получал уже существующий базе объект.
Поэтому, решить проблему с тестами можно было просто убрав явное вешание pk из тестов, оставив эту работу бд:
first_article = Article.objects.create(
# pk=150,
...
)
second_article = Article.objects.create(
# pk=160,
...
)
third_article = Article.objects.create(
# pk=170,
...
)
data = {first_article.pk: 2, second_article.pk: 0, third_article.pk: 1}
И instance.pk проверять следует так:
@receiver(pre_save, sender=Article)
def delete_old_article_image(sender, instance, *args, **kwargs):
if instance.pk is not None:
article = Article.objects.get(pk=instance.pk)
if instance.image and article.image != instance.image:
slide.image.delete(False)