""" Management command для генерации тестовых отметок сигналов. Использование: python manage.py generate_test_marks --satellite_id=1 --days=90 --marks_per_day=5 Параметры: --satellite_id: ID спутника (обязательный) --days: Количество дней для генерации (по умолчанию 90) --marks_per_day: Количество отметок в день (по умолчанию 3) --clear: Удалить существующие отметки перед генерацией """ import random from datetime import timedelta from django.core.management.base import BaseCommand, CommandError from django.utils import timezone from mainapp.models import TechAnalyze, ObjectMark, Satellite, CustomUser class Command(BaseCommand): help = 'Генерирует тестовые отметки сигналов для теханализов выбранного спутника' def add_arguments(self, parser): parser.add_argument( '--satellite_id', type=int, required=True, help='ID спутника для генерации отметок' ) parser.add_argument( '--days', type=int, default=90, help='Количество дней для генерации (по умолчанию 90)' ) parser.add_argument( '--marks_per_day', type=int, default=3, help='Среднее количество отметок в день на теханализ (по умолчанию 3)' ) parser.add_argument( '--clear', action='store_true', help='Удалить существующие отметки перед генерацией' ) def handle(self, *args, **options): satellite_id = options['satellite_id'] days = options['days'] marks_per_day = options['marks_per_day'] clear = options['clear'] # Проверяем существование спутника try: satellite = Satellite.objects.get(id=satellite_id) except Satellite.DoesNotExist: raise CommandError(f'Спутник с ID {satellite_id} не найден') # Получаем теханализы для спутника tech_analyzes = TechAnalyze.objects.filter(satellite=satellite) ta_count = tech_analyzes.count() if ta_count == 0: raise CommandError(f'Нет теханализов для спутника "{satellite.name}"') self.stdout.write(f'Спутник: {satellite.name}') self.stdout.write(f'Теханализов: {ta_count}') self.stdout.write(f'Период: {days} дней') self.stdout.write(f'Отметок в день: ~{marks_per_day}') # Удаляем существующие отметки если указан флаг if clear: deleted_count = ObjectMark.objects.filter( tech_analyze__satellite=satellite ).delete()[0] self.stdout.write( self.style.WARNING(f'Удалено существующих отметок: {deleted_count}') ) # Получаем или создаём тестового пользователя test_users = self._get_or_create_test_users() # Генерируем отметки now = timezone.now() start_date = now - timedelta(days=days) total_marks = 0 marks_to_create = [] for ta in tech_analyzes: # Для каждого теханализа генерируем отметки current_date = start_date # Начальное состояние сигнала (случайное) signal_present = random.choice([True, False]) while current_date < now: # Случайное количество отметок в этот день (от 0 до marks_per_day * 2) day_marks = random.randint(0, marks_per_day * 2) for _ in range(day_marks): # Случайное время в течение дня random_hours = random.randint(0, 23) random_minutes = random.randint(0, 59) mark_time = current_date.replace( hour=random_hours, minute=random_minutes, second=random.randint(0, 59) ) # Пропускаем если время в будущем if mark_time > now: continue # С вероятностью 70% сигнал остаётся в том же состоянии # С вероятностью 30% меняется if random.random() > 0.7: signal_present = not signal_present marks_to_create.append(ObjectMark( tech_analyze=ta, mark=signal_present, created_by=random.choice(test_users), )) total_marks += 1 current_date += timedelta(days=1) # Bulk create для производительности self.stdout.write(f'Создание {total_marks} отметок...') # Создаём партиями по 1000 batch_size = 1000 for i in range(0, len(marks_to_create), batch_size): batch = marks_to_create[i:i + batch_size] ObjectMark.objects.bulk_create(batch) self.stdout.write(f' Создано: {min(i + batch_size, len(marks_to_create))}/{total_marks}') # Обновляем timestamp для созданных отметок (bulk_create не вызывает auto_now_add корректно) self.stdout.write('Обновление временных меток...') # Получаем созданные отметки и обновляем их timestamp created_marks = ObjectMark.objects.filter( tech_analyze__satellite=satellite ).order_by('id') # Распределяем временные метки current_date = start_date mark_index = 0 for ta in tech_analyzes: ta_marks = list(created_marks.filter(tech_analyze=ta).order_by('id')) if not ta_marks: continue # Распределяем отметки по времени time_step = timedelta(days=days) / len(ta_marks) if ta_marks else timedelta(hours=1) for i, mark in enumerate(ta_marks): mark_time = start_date + (time_step * i) # Добавляем случайное смещение mark_time += timedelta( hours=random.randint(0, 23), minutes=random.randint(0, 59) ) if mark_time > now: mark_time = now - timedelta(minutes=random.randint(1, 60)) ObjectMark.objects.filter(id=mark.id).update(timestamp=mark_time) self.stdout.write( self.style.SUCCESS( f'Успешно создано {total_marks} отметок для {ta_count} теханализов' ) ) def _get_or_create_test_users(self): """Получает или создаёт тестовых пользователей для отметок.""" from django.contrib.auth.models import User test_usernames = ['operator1', 'operator2', 'operator3', 'analyst1', 'analyst2'] custom_users = [] for username in test_usernames: user, created = User.objects.get_or_create( username=username, defaults={ 'first_name': username.capitalize(), 'last_name': 'Тестовый', 'is_active': True, } ) custom_user, _ = CustomUser.objects.get_or_create( user=user, defaults={'role': 'user'} ) custom_users.append(custom_user) return custom_users