from django.core.management.base import BaseCommand from django.db import transaction, connection from django.db.models import ProtectedError from django.utils.translation import gettext_lazy as _ from apps.course.models import ( Course, CourseCategory, Lesson, CourseLesson, LessonCompletion, Attachment, CourseAttachment, Glossary, CourseGlossary, Participant ) class Command(BaseCommand): help = _('Clear all course-related data from the database') def add_arguments(self, parser): parser.add_argument( '--force', action='store_true', dest='force', help=_('Force deletion without confirmation'), ) parser.add_argument( '--model', type=str, dest='model', help=_('Specify a single model to clear (e.g., "Course", "Lesson", etc.)'), ) parser.add_argument( '--legacy-only', action='store_true', dest='legacy_only', help=_('Clear only legacy models (before migration to new structure)'), ) def table_exists(self, table_name): """Check if a table exists in the database.""" with connection.cursor() as cursor: cursor.execute( """ SELECT EXISTS ( SELECT FROM information_schema.tables WHERE table_schema = 'public' AND table_name = %s ); """, [table_name] ) return cursor.fetchone()[0] def handle(self, *args, **options): force = options['force'] specific_model = options.get('model') legacy_only = options.get('legacy_only') if not force and not specific_model: confirm = input(_('This will delete ALL course-related data. Are you sure? (yes/no): ')) if confirm.lower() != 'yes': self.stdout.write(self.style.WARNING(_('Operation cancelled.'))) return # Define all models all_models = { 'Course': (Course, 'course_course'), 'CourseCategory': (CourseCategory, 'course_coursecategory'), 'Lesson': (Lesson, 'course_lesson'), 'CourseLesson': (CourseLesson, 'course_courselesson'), 'LessonCompletion': (LessonCompletion, 'course_lessoncompletion'), 'Attachment': (Attachment, 'course_attachment'), 'CourseAttachment': (CourseAttachment, 'course_courseattachment'), 'Glossary': (Glossary, 'course_glossary'), 'CourseGlossary': (CourseGlossary, 'course_courseglossary'), 'Participant': (Participant, 'course_participant'), } # Legacy models (before migration) legacy_models = { 'Course': (Course, 'course_course'), 'CourseCategory': (CourseCategory, 'course_coursecategory'), 'Lesson': (Lesson, 'course_lesson'), 'LessonCompletion': (LessonCompletion, 'course_lessoncompletion'), 'Attachment': (Attachment, 'course_attachment'), 'Glossary': (Glossary, 'course_glossary'), 'Participant': (Participant, 'course_participant'), } models_to_use = legacy_models if legacy_only else all_models if specific_model: # Clear only the specified model if specific_model not in models_to_use: self.stdout.write(self.style.ERROR(_(f'Unknown model: {specific_model}'))) self.stdout.write(self.style.WARNING(_(f'Available models: {", ".join(models_to_use.keys())}'))) return model_info = models_to_use[specific_model] models_to_clear = [(specific_model, model_info[0], model_info[1])] else: # Clear all models in the correct order to avoid foreign key constraints models_to_clear = [] # Order matters for foreign key constraints model_order = [ 'LessonCompletion', 'CourseLesson', 'Lesson', 'CourseAttachment', 'Attachment', 'CourseGlossary', 'Glossary', 'Participant', 'Course', 'CourseCategory' ] for model_name in model_order: if model_name in models_to_use: model_info = models_to_use[model_name] models_to_clear.append((model_name, model_info[0], model_info[1])) # Process each model for model_name, model_class, table_name in models_to_clear: # Check if the table exists if not self.table_exists(table_name): self.stdout.write(self.style.WARNING(_(f'Table {table_name} does not exist, skipping {model_name}'))) continue try: count = model_class.objects.count() model_class.objects.all().delete() self.stdout.write(self.style.SUCCESS(_(f'Deleted {count} {model_name} records'))) except ProtectedError as e: self.stdout.write(self.style.ERROR(_(f'Could not delete {model_name} records due to protected foreign keys'))) self.stdout.write(self.style.ERROR(str(e))) except Exception as e: self.stdout.write(self.style.ERROR(_(f'Error deleting {model_name} records: {str(e)}'))) self.stdout.write(self.style.SUCCESS(_('Course data clearing completed')))