Удалить повторяющиеся строки в Django DB
У меня есть модель, где из-за ошибки кода есть повторяющиеся строки. Теперь мне нужно удалить любые дубликаты из базы данных.
Каждая строка должна иметь уникальную фотографию_ид. Есть ли простой способ их удалить? Или мне нужно сделать что-то вроде этого:
rows = MyModel.objects.all()
for row in rows:
try:
MyModel.objects.get(photo_id=row.photo_id)
except:
row.delete()
Ответы
Ответ 1
Самый простой способ - самый простой способ! Особенно для одного сценария, где производительность даже не имеет значения (если только это не так). Поскольку это не основной код, я бы просто написал первое, что приходит на ум и работает.
# assuming which duplicate is removed doesn't matter...
for row in MyModel.objects.all():
if MyModel.objects.filter(photo_id=row.photo_id).count() > 1:
row.delete()
Как всегда, создайте резервную копию, прежде чем делать это.
Ответ 2
Это может быть быстрее, потому что это позволяет избежать внутреннего фильтра для каждой строки в MyModel.
Поскольку идентификаторы уникальны, если модели отсортированы по ним в порядке возрастания, мы можем отслеживать последний идентификатор, который мы видели, и когда мы проходим по строкам, если мы видим модель с одним и тем же идентификатором, она должна быть дубликат, поэтому мы можем удалить его.
lastSeenId = float('-Inf')
rows = MyModel.objects.all().order_by('photo_id')
for row in rows:
if row.photo_id == lastSeenId:
row.delete() # We've seen this id in a previous row
else: # New id found, save it and check future rows for duplicates.
lastSeenId = row.photo_id
Ответ 3
Вот быстрое решение:
from django.db import connection
query = "SELECT id FROM table_name GROUP BY unique_column HAVING COUNT(unique_column)>1"
cursor = connection.cursor()
cursor.execute(query)
ids_list = [item[0] for item in cursor.fetchall()]
теперь вы можете сделать:
Some_Model.objects.filter(id__in=ids_list).delete()
или если ids_list
слишком велико, чтобы обрабатывать ваши dbms
вы можете сегментировать его на куски, которые могут быть обработаны им:
seg_length = 100
ids_lists = [ids_list[x:x+seg_length] for x in range(0,len(ids_list),seg_length)]
for ids_list in ids_lists:
SomeModel.objects.filter(id__in=ids_list).delete()
Ответ 4
Вместо перебора всей таблицы вы можете просто сделать
count = MyModel.objects.filter(photo_id='some_photo_id').count()
while count >=1:
MyModel.objects.filter(photo_id='some_photo_id')[0].delete()
count -= 1
Ответ 5
Общий и оптимизированный метод в случае необходимости удаления большого количества объектов -
qs = Model.objects.all()
key_set = set()
delete_ids_list = []
for object in qs:
object_key = object.unique_key # photo_id here
if object_key in key_set:
delete_ids_list.append(object.id)
else:
key_set.add(object_key)
Model.objects.filter(id__in=delete_ids_list).delete()