"""修复 config.0006 半路失败:去重 + 补唯一约束/索引,然后 fake 0006。""" from django.core.management.base import BaseCommand from django.db import connection from django.db.models import Max from config.models import PopupPage, Tupianpeizhi def _table_indexes(table): with connection.cursor() as cursor: cursor.execute(f'SHOW INDEX FROM `{table}`') rows = cursor.fetchall() # Key_name, Column_name, Non_unique by_key = {} for row in rows: key_name = row[2] col = row[4] non_unique = row[1] by_key.setdefault(key_name, {'cols': [], 'unique': non_unique == 0}) by_key[key_name]['cols'].append(col) return by_key def _has_unique_on(table, columns): cols = list(columns) for info in _table_indexes(table).values(): if info['unique'] and info['cols'] == cols: return True return False def _drop_index(table, key_name): with connection.cursor() as cursor: cursor.execute(f'ALTER TABLE `{table}` DROP INDEX `{key_name}`') def _add_unique(table, name, columns): cols = ', '.join(f'`{c}`' for c in columns) with connection.cursor() as cursor: cursor.execute(f'ALTER TABLE `{table}` ADD UNIQUE `{name}` ({cols})') def _add_index(table, name, columns): cols = ', '.join(f'`{c}`' for c in columns) with connection.cursor() as cursor: cursor.execute(f'CREATE INDEX `{name}` ON `{table}` ({cols})') class Command(BaseCommand): help = 'config.0006 半路失败时:清重复数据、补约束,再执行 migrate config 0006 --fake' def handle(self, *args, **options): self.stdout.write('1) 清理重复数据…') for row in Tupianpeizhi.objects.values('club_id', 'ImageType').annotate(max_id=Max('id')): n = Tupianpeizhi.objects.filter( club_id=row['club_id'], ImageType=row['ImageType'], ).exclude(id=row['max_id']).delete()[0] if n: self.stdout.write(f' tupianpeizhi 删除 {n} 条重复') for row in PopupPage.objects.values('club_id', 'page_key').annotate(max_id=Max('id')): n = PopupPage.objects.filter( club_id=row['club_id'], page_key=row['page_key'], ).exclude(id=row['max_id']).delete()[0] if n: self.stdout.write(f' popup_page 删除 {n} 条重复') self.stdout.write('2) 检查并补约束/索引…') # popup_page:去掉 page_key 单独唯一,改为 (club_id, page_key) popup_indexes = _table_indexes('popup_page') for key_name, info in popup_indexes.items(): if info['unique'] and info['cols'] == ['page_key']: self.stdout.write(f' 删除 popup_page 旧唯一索引 {key_name}') _drop_index('popup_page', key_name) if not _has_unique_on('popup_page', ['club_id', 'page_key']): self.stdout.write(' 添加 popup_page UNIQUE (club_id, page_key)') _add_unique('popup_page', 'popup_page_club_page_key_uniq', ['club_id', 'page_key']) else: self.stdout.write(' popup_page UNIQUE (club_id, page_key) 已存在') if not _has_unique_on('tupianpeizhi', ['club_id', 'ImageType']): self.stdout.write(' 添加 tupianpeizhi UNIQUE (club_id, ImageType)') _add_unique('tupianpeizhi', 'tupianpeizhi_club_id_ImageType_uniq', ['club_id', 'ImageType']) else: self.stdout.write(' tupianpeizhi UNIQUE (club_id, ImageType) 已存在') lunbo_indexes = _table_indexes('lunbo') if 'lunbo_club_page_type_idx' not in lunbo_indexes: self.stdout.write(' 添加 lunbo 索引 lunbo_club_page_type_idx') _add_index('lunbo', 'lunbo_club_page_type_idx', ['club_id', 'page_key', 'ImageType']) else: self.stdout.write(' lunbo 索引 lunbo_club_page_type_idx 已存在') self.stdout.write(self.style.SUCCESS( '\n完成。请执行:\n' ' python manage.py migrate config 0006 --fake\n' ' python manage.py migrate config\n' ' python manage.py migrate\n' ))