from django.db import models from django.conf import settings from .validators import validate_file_extension from ckeditor_uploader.fields import RichTextUploadingField class Subject(models.Model): name = models.CharField('Название предмета', max_length=100) class Meta: verbose_name = 'Предмет' verbose_name_plural = 'Предметы' def __str__(self): return self.name class Assignment(models.Model): title = models.CharField('Название задания', max_length=255) description = RichTextUploadingField('Описание задания', blank=True, null=True) subject = models.ForeignKey(Subject, on_delete=models.CASCADE, verbose_name='Предмет') is_published = models.BooleanField('Опубликовано', default=True, help_text='Снимите галочку, чтобы скрыть задание (как черновик).') assign_to_all = models.BooleanField('Назначить всем', default=True, help_text='Если включено, задание будет доступно всем ученикам.') assigned_students = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='assigned_assignments', verbose_name='Назначенные ученики', blank=True, limit_choices_to={'role': 'STUDENT'}, help_text='Выберите учеников, если задание не для всех.') created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, limit_choices_to={'role__in': ['TEACHER', 'ADMIN']}, verbose_name='Кем создано') created_at = models.DateTimeField('Дата создания', auto_now_add=True) deadline = models.DateTimeField('Дедлайн', blank=True, null=True, help_text='После этого времени ответы не принимаются.') time_limit = models.PositiveIntegerField('Лимит времени (минуты)', blank=True, null=True, help_text='Например, 235 для 3ч 55м. Оставьте пустым, если без таймера.') class Meta: verbose_name = 'Задание' verbose_name_plural = 'Задания' def __str__(self): return f"{self.title} ({self.subject})" class Question(models.Model): TYPE_CHOICES = ( ('TEXT_AUTO', 'Краткий ответ (автопроверка)'), ('FILE_MANUAL', 'Файл/Развернутый ответ (ручная проверка)'), ('TABLE_AUTO', 'Таблица (2 столбца, автопроверка)'), ) assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE, related_name='questions', verbose_name='Задание') text = RichTextUploadingField('Текст задачи') attached_file = models.FileField('Файл (опционально)', upload_to='questions/', blank=True, null=True, validators=[validate_file_extension]) question_type = models.CharField('Тип ответа', max_length=20, choices=TYPE_CHOICES, default='TEXT_AUTO') table_rows = models.PositiveIntegerField('Количество строк в таблице', default=2, blank=True, null=True, help_text='Укажите количество строк. Столбцов всегда 2.') correct_answer = models.CharField('Правильный ответ (для автопроверки)', max_length=255, blank=True, null=True, help_text='Оставьте пустым для ручной проверки. Для таблицы вводите ответы в формате "Ответ1|Ответ2;Ответ3|Ответ4" (строки через точку с запятой, столбцы через прямую черту).') order = models.PositiveIntegerField('Порядок', default=0) class Meta: verbose_name = 'Задача' verbose_name_plural = 'Задачи' ordering = ['order', 'id'] def __str__(self): return f"Задача {self.id} к {self.assignment.title}" class Submission(models.Model): STATUS_CHOICES = ( ('IN_PROGRESS', 'В процессе выполнения'), ('PENDING', 'Ожидает проверки'), ('GRADED', 'Проверено'), ) assignment = models.ForeignKey(Assignment, on_delete=models.CASCADE, related_name='submissions', verbose_name='Задание') student = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, limit_choices_to={'role': 'STUDENT'}, verbose_name='Ученик') grade = models.CharField('Оценка', max_length=10, blank=True, null=True) teacher_feedback = models.TextField('Комментарий учителя', blank=True, null=True) status = models.CharField('Статус', max_length=20, choices=STATUS_CHOICES, default='PENDING') started_at = models.DateTimeField('Время начала', blank=True, null=True) submitted_at = models.DateTimeField('Дата отправки', auto_now_add=True) is_time_expired = models.BooleanField('Время вышло', default=False) class Meta: verbose_name = 'Ответ ученика' verbose_name_plural = 'Ответы учеников' def __str__(self): return f"Ответ от {self.student.username} на {self.assignment.title}" class Answer(models.Model): submission = models.ForeignKey(Submission, on_delete=models.CASCADE, related_name='answers', verbose_name='Решение (Submission)') question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='answers', verbose_name='Задача') text_answer = models.TextField('Текстовый ответ', blank=True, null=True) file_answer = models.FileField('Файл с ответом', upload_to='answers/%Y/%m/%d/', blank=True, null=True, validators=[validate_file_extension]) is_correct = models.BooleanField('Правильно?', null=True, blank=True) points = models.PositiveIntegerField('Баллы', blank=True, null=True) comment = models.TextField('Комментарий', blank=True, null=True) class Meta: verbose_name = 'Ответ на задачу' verbose_name_plural = 'Ответы на задачи' def __str__(self): return f"Ответ на {self.question}"