Удалите все объекты в Django, кроме последних N (N - большое, около 1000)

Какой самый быстрый способ удалить все объекты, кроме последней 1000?

Я могу сделать это медленно:

last_events = Event.objects.filter(user=user).order_by('-created')[:1000].values_list('id', flat=True) 

Event.objects.filter(user=user).exclude(id__in=list(last_events)).delete()

Но я бы не хотел загружать такой длинный запрос в мою БД.

Я думал, что не могу найти ID элемента границы и удалить все объекты перед этим элементом:

last_events = Event.objects.filter(user=user).order_by('-created')[:1000].last()

Но получил: TypeError: Cannot reverse a query once a slice has been taken.

Я также пробовал:

last_events = Event.objects.filter(user=user).order_by('-created')[:1000][-1]

Но получил: AssertionError: Negative indexing is not supported.

Вам просто нужно изменить порядок, используемый для построения SQL, и использовать первые 1000 вместо последних, например, так:

last_events = Event.objects.filter(user=user).order_by('+created')[:1000]
Event.objects.filter(user=user).exclude(id__in=list(last_events)).delete()

То, что вы попробовали сначала, является правильным способом. Иногда delete() может работать медленно. Вы можете избежать его медлительности, если вас не волнует следующее:

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

Если вам удобно работать с ними, вы можете использовать _raw_delete() начиная с Django 1.5+. Поскольку это приватный метод, мне не очень нравится вызывать эти методы.

Вторым ответом может быть необработанный SQL-запрос, такой как:

delete from table_events 
where user_id={user_id} 
  and id not in (
    select id
    from table_events
    where user_id={user_id}
    order by created desc
    offset {N}
  )

Перед использованием обоих способов следует хорошо подумать. Отношения и функциональные возможности Django под капотом будут для вас неприемлемы. Вы должны позаботиться об этих проблемах самостоятельно.

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