Files
dbstorage/dbapp/mainapp/management/commands/generate_test_marks.py

205 lines
8.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
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