/
tebo
/
BubblesCode
Обзор
Документация
Войти
/
tebo
/
BubblesCode
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
problems/models.py
161 строка
7 KB
tebo
first_commit
03 июн 2026, 15:20
03 июн 2026, 15:20
e3a5c0b
Код
Авторство
О чём код?
from django.db import models from django.conf import settings from django.urls import reverse from ckeditor.fields import RichTextField # --- Добавьте эти импорты для сигналов --- from django.db.models.signals import post_save from django.dispatch import receiver class Problem(models.Model): """ Основная модель для учебной задачи. """ title = models.CharField( max_length=255, verbose_name="Название задачи" ) description = RichTextField(verbose_name="Описание задачи") theory_article = models.ForeignKey( 'theory.TheoryArticle', on_delete=models.SET_NULL, blank=True, null=True, verbose_name="Статья с теорией", help_text="Свяжите задачу с теоретическим материалом." ) initial_code = models.TextField( verbose_name="Начальный код для ученика", blank=True, help_text="Этот код будет вставлен в редактор по умолчанию. Используйте '# Ваш код здесь' для установки курсора." ) solution_code = models.TextField( verbose_name="Образцовое решение", blank=True, help_text="Код правильного решения. Будет показан ученику после успешного прохождения тестов." ) is_published = models.BooleanField( default=True, verbose_name="Опубликовано", help_text="Снимите галочку, чтобы скрыть задачу от всех, кроме администраторов." ) allowed_users = models.ManyToManyField( settings.AUTH_USER_MODEL, blank=True, verbose_name="Пользователи с доступом", help_text="Если здесь выбраны пользователи, задача будет доступна только им (и администраторам). Если поле пустое, задача будет публичной." ) # --- Тип задачи и интерактивность --- use_interactive_runner = models.BooleanField( default=False, verbose_name="Использовать интерактивный запуск?", help_text="Включите для задач, использующих интерактивный запуск." ) is_solution_interactive = models.BooleanField( default=False, verbose_name="Сделать образцовое решение интерактивным?", help_text="Если включено, код решения будет запускаться через Skulpt, а не просто отображаться как текст." ) interactive_example_code = models.TextField( blank=True, verbose_name="Интерактивный пример (Python-код)", help_text="Код на Python, который будет отображаться как интерактивный пример (используя Skulpt)." ) class Meta: verbose_name = "Задача" verbose_name_plural = "Задачи" ordering = ['id'] def __str__(self): return f"#{self.id}: {self.title}" def get_absolute_url(self): return reverse('problems:problem_detail', args=[self.pk]) class Example(models.Model): """ Примеры входных и выходных данных, которые видит пользователь. """ problem = models.ForeignKey(Problem, related_name='examples', on_delete=models.CASCADE) input_data = models.TextField(verbose_name="Входные данные") expected_output = models.TextField(verbose_name="Ожидаемый выход") explanation = models.TextField(blank=True, verbose_name="Пояснение") def __str__(self): return f"Пример для задачи #{self.problem.id}" class TestCase(models.Model): """ Тест-кейсы для автоматической проверки кода. Не видны пользователю. """ problem = models.ForeignKey(Problem, related_name='test_cases', on_delete=models.CASCADE) input_data = models.TextField(verbose_name="Входные данные для функции") expected_output = models.TextField(verbose_name="Ожидаемый результат (Python литерал)") def __str__(self): return f"Тест-кейс для задачи #{self.problem.id}" class Submission(models.Model): """ Модель для хранения истории решений задач пользователями. """ user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) problem = models.ForeignKey(Problem, on_delete=models.CASCADE) submitted_code = models.TextField(verbose_name="Отправленный код") passed_all_tests = models.BooleanField(default=False, verbose_name="Все тесты пройдены") timestamp = models.DateTimeField(auto_now_add=True, verbose_name="Время отправки") class Meta: ordering = ['-timestamp'] def __str__(self): return f"Решение от {self.user} для '{self.problem.title}'" @receiver(post_save, sender=Submission) def award_points_on_success(sender, instance, created, **kwargs): """ Начисляет баллы пользователю за первое успешное решение задачи. """ # Срабатываем только для НОВЫХ записей, которые прошли все тесты if created and instance.passed_all_tests: user = instance.user problem = instance.problem # Проверяем, есть ли у пользователя ДРУГИЕ успешные решения этой же задачи. previous_solves = Submission.objects.filter( user=user, problem=problem, passed_all_tests=True ).exclude(pk=instance.pk).exists() # Если других решений нет, значит это первое, и мы начисляем баллы. if not previous_solves: user.points += 10 # Начисляем 10 баллов за задачу user.save(update_fields=['points']) # --------------------------------------------- class UserCodeDraft(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) problem = models.ForeignKey(Problem, on_delete=models.CASCADE) code = models.TextField(verbose_name="Сохраненный код") last_updated = models.DateTimeField(auto_now=True, verbose_name="Последнее обновление") class Meta: unique_together = ('user', 'problem') verbose_name = "Черновик кода" verbose_name_plural = "Черновики кода" def __str__(self): return f"Черновик от {self.user} для '{self.problem.title}'"