""" Management command для генерации тестовых отметок сигналов. Использование: python manage.py generate_test_marks --satellite_id=1 --user_id=1 --date_range=10.10.2025-15.10.2025 Параметры: --satellite_id: ID спутника (обязательный) --user_id: ID пользователя CustomUser (обязательный) --date_range: Диапазон дат в формате ДД.ММ.ГГГГ-ДД.ММ.ГГГГ (обязательный) --clear: Удалить существующие отметки перед генерацией Особенности: - Генерирует отметки только в будние дни (пн-пт) - Время отметок: утро с 8:00 до 11:00 - Одна отметка в день для всех сигналов спутника - Все отметки в один день имеют одинаковый timestamp (пакетное сохранение) - Все отметки имеют значение True (сигнал присутствует) """ import random from datetime import datetime, 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( '--user_id', type=int, required=True, help='ID пользователя CustomUser - автор всех отметок' ) parser.add_argument( '--date_range', type=str, required=True, help='Диапазон дат в формате ДД.ММ.ГГГГ-ДД.ММ.ГГГГ (например: 10.10.2025-15.10.2025)' ) parser.add_argument( '--clear', action='store_true', help='Удалить существующие отметки перед генерацией' ) def handle(self, *args, **options): satellite_id = options['satellite_id'] user_id = options['user_id'] date_range = options['date_range'] clear = options['clear'] # Проверяем существование пользователя try: custom_user = CustomUser.objects.select_related('user').get(id=user_id) except CustomUser.DoesNotExist: raise CommandError(f'Пользователь CustomUser с ID {user_id} не найден') # Парсим диапазон дат try: start_str, end_str = date_range.split('-') start_date = datetime.strptime(start_str.strip(), '%d.%m.%Y') end_date = datetime.strptime(end_str.strip(), '%d.%m.%Y') # Делаем timezone-aware start_date = timezone.make_aware(start_date) end_date = timezone.make_aware(end_date) if start_date > end_date: raise CommandError('Начальная дата должна быть раньше конечной') except ValueError as e: raise CommandError( f'Неверный формат даты. Используйте ДД.ММ.ГГГГ-ДД.ММ.ГГГГ (например: 10.10.2025-15.10.2025). Ошибка: {e}' ) # Проверяем существование спутника try: satellite = Satellite.objects.get(id=satellite_id) except Satellite.DoesNotExist: raise CommandError(f'Спутник с ID {satellite_id} не найден') # Получаем теханализы для спутника tech_analyzes = list(TechAnalyze.objects.filter(satellite=satellite)) ta_count = len(tech_analyzes) 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'Пользователь: {custom_user}') self.stdout.write(f'Период: {start_str} - {end_str} (только будние дни)') self.stdout.write(f'Время: 8:00 - 11:00') # Удаляем существующие отметки если указан флаг if clear: deleted_count = ObjectMark.objects.filter( tech_analyze__satellite=satellite ).delete()[0] self.stdout.write( self.style.WARNING(f'Удалено существующих отметок: {deleted_count}') ) # Генерируем отметки total_marks = 0 marks_to_create = [] workdays_count = 0 current_date = start_date # Включаем конечную дату в диапазон end_date_inclusive = end_date + timedelta(days=1) while current_date < end_date_inclusive: # Проверяем, что это будний день (0=пн, 4=пт) if current_date.weekday() < 5: workdays_count += 1 # Генерируем случайное время в диапазоне 8:00-11:00 random_hour = random.randint(8, 10) random_minute = random.randint(0, 59) random_second = random.randint(0, 59) mark_time = current_date.replace( hour=random_hour, minute=random_minute, second=random_second, microsecond=0 ) # Создаём отметки для всех теханализов с одинаковым timestamp for ta in tech_analyzes: marks_to_create.append(ObjectMark( tech_analyze=ta, mark=True, # Всегда True timestamp=mark_time, created_by=custom_user, )) total_marks += 1 current_date += timedelta(days=1) # Bulk create для производительности self.stdout.write(f'Рабочих дней: {workdays_count}') 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}') self.stdout.write( self.style.SUCCESS( f'Успешно создано {total_marks} отметок для {ta_count} теханализов за {workdays_count} рабочих дней' ) )