Удаление дублей и установка составного уникального ключа

1570 0
Иногда случается, что при создании моделей мы забываем про ключи для обеспечения уникальности полей. А вспоминаем об этом только когда начинают сыпаться ошибки из-за накопившихся дублей.

Эта заметка о решении этой проблемы "одним ударом"

Для этого мы сделаем самописную миграцию с небольшой функцией для удаления дублей:
import django.core.validators
from django.db import migrations, models

def _del_double(apps, schema_editor):
    '''
    Функция удаляющая из модели все дубли.
    Дубли ищем по составному уникальному ключу из двух полей 
    key_1 и key_2
    '''
    MyModel = apps.get_model("<My_app>", "<My_model>")
    for record in MyModel.objects.values('key_1', 'key_2').distinct():
        # Накапливаем список дублей
        double_list = UserSettings.objects.filter(
                key_1=record['key_1'],
                key_2=record['key_2']
        ).values_list('id', flat=True)[1:]
        
        # Поочередно удаляем дубли
        for double_pk in double_list:
            MyModel.objects.exclude(value__isnull=True).filter(
                pk=double_pk
            ).delete()

class Migration(migrations.Migration):
    '''
    Миграция объединяющая удаление дублей и последующее создание 
    уникальных ключей
    '''
    dependencies = [
        ('<My_app', '<Previous_migration>'),
    ]
    operations = [
        migrations.RunPython(_del_double),
        migrations.AlterUniqueTogether(
            name='mymodel',
            unique_together=set([('key_1', 'key_2')]),
        ),
    ]
Также не забываем добавить в нашу модель:
class MyModel(models.Model):
    class Meta:
        unique_together = ('key_1', 'key_2')

Вот и всё. После запуска мы получим модель очищенную от дублей и готовую к дальнейшей работе без дублей.

Комментарии

Контактные данные

 Россия, г. Москва