Получение предыдущей версии объекта в методе save

В Django довольно часто возникает необходимость получения предыдущей версии инстанса модели при сохранении.

В самом простом и очевидном варианте это делается так:

class MyModel(models.Model):
    def save(self, *args, **kwargs):
        old_instance = None
        if self.pk
            old_instance = MyModel.objects.get(pk=self.pk)

Всё бы хорошо, но иногда бывает так, что pk указан, а в базе такого объекта нет. Это случается, например, когда вы хотите вручную восстановить удалённый объект:

MyModel.objects.create(pk=10, field1='value1')

Указание идентификатора при создании объекта - это не ошибка, всё будет работать, но только до тех пор, пока вы не решите переопределить save используя код, приведённый в начале.

Конечно, можно делать запрос в базу всегда, не проверяя идентификатор, но это не очень экономно, поэтому обычно поступают так:

class MyModel(models.Model):
    def save(self, *args, **kwargs):
        if not self.pk:
            old_instance = None
        else:
            try:
                old_instance = MyModel.objects.get(pk=self.pk)
            except MyModel.DoesNotExist:
                old_instance = None

Есть и другой, более короткий и элегантный вариант:

class MyModel(models.Model):
    def save(self, *args, **kwargs):
        try:
            if not self.pk:
                raise self.__class__.DoesNotExist()
            old_instance = self.__class__.objects.get(pk=self.pk)
        except self.__class__.DoesNotExist:
            old_instance = None

Не пугайтесь self.__class__ - можно и явно указать имя модели, но это не очень удобно при копировании кода в другую модель и при наследовании.