Исходный код assignments.models

"""
Модели данных для системы проверки домашних заданий.

Содержит модели для:
- Профилей пользователей (студенты и преподаватели)
- Домашних заданий
- Отправленных работ студентов
"""

import os

from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver

User = get_user_model()


[документация] def validate_file_size(file): """ Валидатор размера файла (максимум 10 МБ). Args: file: Загружаемый файл Raises: ValidationError: Если размер файла превышает лимит """ max_size_mb = 10 if file.size > max_size_mb * 1024 * 1024: raise ValidationError(f"Максимальный размер файла {max_size_mb}МБ. Ваш файл: {file.size / (1024 * 1024):.2f}МБ")
[документация] def validate_file_extension(file): """ Валидатор расширения файла. Args: file: Загружаемый файл Raises: ValidationError: Если расширение файла не разрешено """ ext = os.path.splitext(file.name)[1].lower() valid_extensions = [".pdf", ".doc", ".docx", ".txt", ".py", ".zip", ".jpg", ".jpeg", ".png"] if ext not in valid_extensions: raise ValidationError(f"Неподдерживаемый формат файла. Разрешены: {', '.join(valid_extensions)}")
[документация] class UserProfile(models.Model): """Профиль пользователя с ролью""" ROLE_CHOICES = [ ("student", "Студент"), ("teacher", "Преподаватель"), ] user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile") role = models.CharField(max_length=10, choices=ROLE_CHOICES, default="student", verbose_name="Роль") class Meta: verbose_name = "Профиль пользователя" verbose_name_plural = "Профили пользователей" def __str__(self): return f"{self.user.username} - {self.get_role_display()}" @property def is_student(self): return self.role == "student" @property def is_teacher(self): return self.role == "teacher"
[документация] @receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): """Автоматически создаем профиль при создании пользователя""" if created: UserProfile.objects.create(user=instance)
[документация] @receiver(post_save, sender=User) def save_user_profile(sender, instance, **kwargs): """Сохраняем профиль при сохранении пользователя""" if hasattr(instance, "profile"): instance.profile.save()
[документация] class Course(models.Model): """Модель курса""" title = models.CharField(max_length=200, verbose_name="Название курса") description = models.TextField(verbose_name="Описание курса") teachers = models.ManyToManyField( User, related_name="teaching_courses", verbose_name="Преподаватели", limit_choices_to={"profile__role": "teacher"}, ) students = models.ManyToManyField( User, related_name="enrolled_courses", blank=True, verbose_name="Студенты", limit_choices_to={"profile__role": "student"}, ) created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания") class Meta: verbose_name = "Курс" verbose_name_plural = "Курсы" ordering = ["title"] def __str__(self): return self.title
[документация] class Homework(models.Model): """Модель домашнего задания""" course = models.ForeignKey(Course, on_delete=models.CASCADE, related_name="homeworks", verbose_name="Курс") title = models.CharField(max_length=200, verbose_name="Заголовок") description = models.TextField(verbose_name="Описание") due_date = models.DateTimeField(verbose_name="Срок сдачи") created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания") class Meta: verbose_name = "Домашнее задание" verbose_name_plural = "Домашние задания" ordering = ["-created_at"] def __str__(self): return f"{self.course.title} - {self.title}"
[документация] class Submission(models.Model): """Модель отправки работы студентом""" homework = models.ForeignKey( Homework, on_delete=models.CASCADE, related_name="submissions", verbose_name="Домашнее задание" ) student = models.ForeignKey(User, on_delete=models.CASCADE, related_name="submissions", verbose_name="Студент") solution_file = models.FileField( upload_to="submissions/", verbose_name="Файл с решением", validators=[validate_file_size, validate_file_extension], ) submitted_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата отправки") grade = models.IntegerField(null=True, blank=True, verbose_name="Оценка") feedback = models.TextField(blank=True, verbose_name="Отзыв преподавателя") class Meta: verbose_name = "Отправка работы" verbose_name_plural = "Отправки работ" ordering = ["-submitted_at"] unique_together = ["homework", "student"] def __str__(self): return f"{self.student.username} - {self.homework.title}"
[документация] class CourseEnrollmentRequest(models.Model): """Модель заявки студента на зачисление на курс""" STATUS_CHOICES = [ ("pending", "На рассмотрении"), ("approved", "Одобрена"), ("rejected", "Отклонена"), ] course = models.ForeignKey( Course, on_delete=models.CASCADE, related_name="enrollment_requests", verbose_name="Курс", ) student = models.ForeignKey( User, on_delete=models.CASCADE, related_name="course_requests", verbose_name="Студент", limit_choices_to={"profile__role": "student"}, ) status = models.CharField( max_length=10, choices=STATUS_CHOICES, default="pending", verbose_name="Статус", ) message = models.TextField( blank=True, verbose_name="Сообщение от студента", help_text="Опциональное сообщение преподавателю", ) created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата подачи") processed_at = models.DateTimeField(null=True, blank=True, verbose_name="Дата обработки") processed_by = models.ForeignKey( User, on_delete=models.SET_NULL, null=True, blank=True, related_name="processed_requests", verbose_name="Обработал", ) class Meta: verbose_name = "Заявка на курс" verbose_name_plural = "Заявки на курсы" ordering = ["-created_at"] unique_together = ["course", "student"] def __str__(self): return f"{self.student.username}{self.course.title} ({self.get_status_display()})"