Удаление экземпляра перед сохранением нового (метод сохранения модели Django)

Я хочу ограничить количество записей в моей модели максимум 10 строками для каждого пользователя (модель имеет внешний ключ к модели пользователя). Какова наилучшая практика для этого?

Я думал переопределить метод сохранения, выполнить проверку и удалить перед сохранением:

def save(self, *args, **kwargs):
 if MyModel.objects.filter(user=self.user).count() >= 10:
     oldest_record =         MyModel.objects.filter(user=self.user).order_by('created_at').first()
 oldest_record.delete()
 super().save(*args, **kwargs)

Но мне интересно, является ли это хорошим решением, лучше ли (и как это сделать) обеспечить это на уровне базы данных, и возможны ли проблемы, когда один и тот же пользователь сохраняет два экземпляра одновременно (хотя это очень маловероятно). Есть ли опыт использования чего-то подобного?

Вы можете повысить эффективность, используя user_id вместо user, так как это предотвращает выборку пользователя.

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

def save(self, *args, **kwargs):
    if instance._state.adding:
        items = (
            MyModel.objects.filter(user_id=self.user_id)
            .order_by('created_at')
            .only('pk')[9:]
        )
        if items:
            MyModel.objects.filter(pk__in={item.pk for item in items}).delete()
    super().save(*args, **kwargs)

Но переопределение .save() методов, сигналов и т.д. можно обойти с помощью массовых операций (например, bulk create).

Если лучше (и как это сделать) обеспечить это на уровне базы данных.

Вы можете обеспечить это на уровне базы данных с помощью UniqueConstraint, которая делает комбинацию user_id и первичного ключа уникальной по модулю десять. В этом случае логика переходит к выбору хорошего первичного ключа.

Это означает, что для пользователя мы можем назначить ему, например, предметы с первичными ключами 51, 26, 32 и т.д., но не 31, поскольку …1 уже "выбран".

Возможно, лучше периодически запускать команду управления для очистки старых записей, а на переднем конце всегда ограничивать количество MyModel для пользователя десятью. Это, вероятно, достаточно надежно.

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