Удалить повторяющиеся строки в Django DB - PullRequest
12 голосов
/ 23 января 2012

У меня есть модель, в которой из-за ошибки в коде появляются повторяющиеся строки.Теперь мне нужно удалить любые дубликаты из базы данных.

Каждая строка должна иметь уникальный photo_id.Есть ли простой способ их удалить?Или мне нужно сделать что-то вроде этого:

rows = MyModel.objects.all()
for row in rows:
    try:
        MyModel.objects.get(photo_id=row.photo_id)
    except:
        row.delete()

Ответы [ 5 ]

24 голосов
/ 23 января 2012

Самый простой способ - самый простой! Особенно для сценариев, где производительность даже не имеет значения (если это не так). Поскольку это не основной код, я просто напишу первое, что приходит на ум, и работает .

# 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()

Как всегда, сделайте резервную копию, прежде чем делать это.

13 голосов
/ 24 апреля 2012

Это может быть быстрее, потому что избегает внутреннего фильтра для каждой строки в 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 голосов
/ 06 августа 2013

Вот быстрое решение:

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 был слишком велик, чтобы быть обработанным вашими БД

Вы можете сегментировать его на куски, которые могут быть обработаны им:

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()
0 голосов
/ 23 мая 2019

Общий и оптимизированный метод в случае необходимости удаления большого количества объектов -

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()
0 голосов
/ 05 мая 2018

Вместо перебора всей таблицы вы можете просто сделать

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...