fix: fixed admin bug and added 12rojgpouehgsrfojn

This commit is contained in:
Андрей Сумин
2025-03-02 13:34:54 +03:00
parent f95d6c1c6c
commit 5e8742ee10
13 changed files with 75 additions and 140 deletions
@@ -1,4 +1,4 @@
# Generated by Django 5.1.6 on 2025-03-02 06:13
# Generated by Django 5.1.6 on 2025-03-02 10:28
import apps.competition.models
import datetime
@@ -20,8 +20,8 @@ class Command(BaseCommand):
self.stdout.write("Starting data generation...")
users = self.create_users(5)
competitions = self.create_competitions(2, users)
self.reviewers = self.create_reviewers(2)
tasks = self.create_tasks(competitions)
self.reviewers = self.create_reviewers(1)
self.create_submissions(tasks, users)
self.create_states(competitions, users)
self.stdout.write("Data generation completed.")
@@ -108,8 +108,14 @@ class Command(BaseCommand):
)
tasks.append(task)
self.stdout.write(f"Created task: {title} (type: {task_type})")
self.add_reviewers_to_task(tasks)
return tasks
def add_reviewers_to_task(self, tasks):
for task in tasks:
task.reviewers.set(self.reviewers)
task.save()
def create_submissions(self, tasks, users):
for task in tasks:
# Each task will get between 1 and 3 submissions
@@ -133,15 +139,6 @@ class Command(BaseCommand):
self.stdout.write(
f"Created submission for task '{task.title}' by user '{user.username}'"
)
self.add_reviewers(submission)
def add_reviewers(self, submission):
for reviewer in self.reviewers:
if random.choice([True, False]):
Review.objects.create(
submission=submission,
reviewer=reviewer,
)
def create_states(self, competitions, users):
# For each competition, create a State for some of its participants
@@ -1,6 +1,5 @@
# Generated by Django 5.1.6 on 2025-03-02 09:31
# Generated by Django 5.1.6 on 2025-03-02 10:28
import django.db.models.deletion
import uuid
from django.db import migrations, models
@@ -10,10 +9,21 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('task', '0003_remove_competitiontask_attachments'),
]
operations = [
migrations.CreateModel(
name='Review',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('evaluation', models.JSONField(blank=True, default=list, null=True, verbose_name='выполнение')),
('state', models.CharField(choices=[('not_checked', 'Not Checked'), ('checking', 'Checking'), ('checked', 'Checked')], default='not_checked', max_length=11, verbose_name='состояние')),
],
options={
'verbose_name': 'проверка',
'verbose_name_plural': 'проверки',
},
),
migrations.CreateModel(
name='Reviewer',
fields=[
@@ -27,18 +37,4 @@ class Migration(migrations.Migration):
'verbose_name_plural': 'проверяющие',
},
),
migrations.CreateModel(
name='Review',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('evaluation', models.JSONField(blank=True, default=list, null=True, verbose_name='выполнение')),
('state', models.CharField(choices=[('not_checked', 'Not Checked'), ('checking', 'Checking'), ('checked', 'Checked')], default='not_checked', max_length=11, verbose_name='состояние')),
('submission', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='task.competitiontasksubmission', verbose_name='посылка')),
('reviewer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='review.reviewer', verbose_name='проверяющий')),
],
options={
'verbose_name': 'проверка',
'verbose_name_plural': 'проверки',
},
),
]
@@ -0,0 +1,27 @@
# Generated by Django 5.1.6 on 2025-03-02 10:28
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('review', '0001_initial'),
('task', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='review',
name='submission',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='task.competitiontasksubmission', verbose_name='посылка'),
),
migrations.AddField(
model_name='review',
name='reviewer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='review.reviewer', verbose_name='проверяющий'),
),
]
+1 -1
View File
@@ -27,7 +27,7 @@ class Review(BaseModel):
reviewer = models.ForeignKey(Reviewer, on_delete=models.CASCADE,
verbose_name="проверяющий")
submission = models.ForeignKey(
"CompetitionTaskSubmission",
"task.CompetitionTaskSubmission",
on_delete=models.CASCADE,
related_name="reviews",
verbose_name="посылка"
+1 -1
View File
@@ -19,7 +19,7 @@ class CompetitionTaskSubmissionAdmin(admin.ModelAdmin):
list_display = ("task", "user", "status",)
search_fields = ("task__id", "task__title", "user__username", "user__email")
filter = ("plagiarism_checked",)
ordering = "-timestamp"
ordering = ["-timestamp"]
def has_add_permission(self, request, obj=None):
return False
@@ -1,4 +1,4 @@
# Generated by Django 5.1.6 on 2025-03-02 06:13
# Generated by Django 5.1.6 on 2025-03-02 10:28
import apps.task.models
import django.db.models.deletion
@@ -13,6 +13,7 @@ class Migration(migrations.Migration):
dependencies = [
('competition', '0001_initial'),
('review', '0001_initial'),
('user', '0001_initial'),
]
@@ -30,6 +31,7 @@ class Migration(migrations.Migration):
('points', models.IntegerField(blank=True, null=True, verbose_name='баллы за задание')),
('answer_file_path', models.TextField(blank=True, default='stdout', help_text='Путь до файла в котором ожидается результат. Пример: stdout или ./output.txt', null=True, verbose_name='куда сделать вывод программы участнику')),
('competition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='competition.competition')),
('reviewers', models.ManyToManyField(blank=True, to='review.reviewer')),
],
options={
'verbose_name': 'задание',
@@ -40,10 +42,10 @@ class Migration(migrations.Migration):
name='CompetitionTaskAttachment',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('file', models.FileField(upload_to=apps.task.models.CompetitionTaskAttachment.file_upload_at)),
('bind_at', models.FilePathField()),
('public', models.BooleanField(default=False)),
('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='task.competitiontask')),
('file', models.FileField(upload_to=apps.task.models.CompetitionTaskAttachment.file_upload_at, verbose_name='файл')),
('bind_at', models.FilePathField(verbose_name='путь сохранения')),
('public', models.BooleanField(default=False, verbose_name='публичный')),
('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='task.competitiontask', verbose_name='задание')),
],
options={
'abstract': False,
@@ -67,7 +69,7 @@ class Migration(migrations.Migration):
name='CompetitionTaskSubmission',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('status', models.CharField(choices=[('sent', 'Sent'), ('checking', 'Checking'), ('checked', 'Checked')], default='sent', max_length=8)),
('status', models.CharField(choices=[('sent', 'Sent'), ('checking', 'Checking'), ('checked', 'Checked')], default='sent', max_length=8, verbose_name='статус')),
('content', models.FileField(upload_to=apps.task.models.CompetitionTaskSubmission.submission_content_upload_to)),
('stdout', models.FileField(blank=True, null=True, upload_to=apps.task.models.CompetitionTaskSubmission.submission_stdout_upload_to)),
('result', models.JSONField(blank=True, default=None, null=True)),
@@ -1,40 +0,0 @@
# Generated by Django 5.1.6 on 2025-03-02 08:50
import apps.task.models
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('task', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='competitiontask',
name='attachments',
field=models.ManyToManyField(blank=True, related_name='tasks_attachments', to='task.competitiontaskattachment'),
),
migrations.AlterField(
model_name='competitiontaskattachment',
name='bind_at',
field=models.FilePathField(verbose_name='путь сохранения'),
),
migrations.AlterField(
model_name='competitiontaskattachment',
name='file',
field=models.FileField(upload_to=apps.task.models.CompetitionTaskAttachment.file_upload_at, verbose_name='файл'),
),
migrations.AlterField(
model_name='competitiontaskattachment',
name='public',
field=models.BooleanField(default=False, verbose_name='публичный'),
),
migrations.AlterField(
model_name='competitiontaskattachment',
name='task',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='task.competitiontask', verbose_name='задание'),
),
]
@@ -1,17 +0,0 @@
# Generated by Django 5.1.6 on 2025-03-02 09:31
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('task', '0002_competitiontask_attachments_and_more'),
]
operations = [
migrations.RemoveField(
model_name='competitiontask',
name='attachments',
),
]
+14 -27
View File
@@ -6,7 +6,7 @@ from tinymce.models import HTMLField
from apps.competition.models import Competition
from apps.core.models import BaseModel
from apps.review.models import Review, ReviewStatusChoices
from apps.review.models import Review, ReviewStatusChoices, Reviewer
from apps.user.models import User
@@ -50,6 +50,9 @@ class CompetitionTask(BaseModel):
default="stdout",
)
# only when "review" type
reviewers = models.ManyToManyField(Reviewer, blank=True)
def __str__(self):
return self.title
@@ -93,10 +96,8 @@ class CompetitionTaskSubmission(BaseModel):
def submission_stdout_upload_to(instance, filename) -> str:
return f"/submissions/{instance.id}/stdout"
user = models.ForeignKey(User, on_delete=models.CASCADE,
verbose_name="пользователь")
task = models.ForeignKey(CompetitionTask, on_delete=models.CASCADE,
verbose_name="задание")
user = models.ForeignKey(User, on_delete=models.CASCADE)
task = models.ForeignKey(CompetitionTask, on_delete=models.CASCADE)
status = models.CharField(
choices=StatusChoices.choices,
@@ -106,38 +107,24 @@ class CompetitionTaskSubmission(BaseModel):
)
# code or text or file
content = models.FileField(upload_to=submission_content_upload_to,
verbose_name="код/файл посылки")
content = models.FileField(upload_to=submission_content_upload_to)
# only if task type is checker
stdout = models.FileField(
upload_to=submission_stdout_upload_to, null=True, blank=True,
verbose_name="вывод чекера"
upload_to=submission_stdout_upload_to, null=True, blank=True
)
# depends on task type:
# - input: {"correct": boolean}
# - file: {"total_points": integer, "by_criteria": ["criteria_name": integer]}
# - code: {"correct": boolean}
result = models.JSONField(default=None, null=True, blank=True,
verbose_name="результат проверки")
result = models.JSONField(default=None, null=True, blank=True)
# just more readable result representation, maybe will be calcuated somehow more complex depends on criteria
earned_points = models.IntegerField(null=True, blank=True,
verbose_name="получено баллов")
earned_points = models.IntegerField(null=True, blank=True)
checked_at = models.DateTimeField(null=True, blank=True,
verbose_name="дата и время проверки")
plagiarism_checked = models.BooleanField(default=False,
verbose_name="проверено на плагиат")
timestamp = models.DateTimeField(auto_now_add=True,
verbose_name="дата отправки")
def __str__(self):
return str(self.id)
class Meta:
verbose_name = "посылка"
verbose_name_plural = "посылки"
checked_at = models.DateTimeField(null=True, blank=True)
plagiarism_checked = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
def send_on_review(self):
if not self.task.reviewers.exists():
@@ -158,7 +145,7 @@ class CompetitionTaskSubmission(BaseModel):
.order_by("pending_count")
.first()
)
Review.objects.create(
review = Review.objects.create(
reviewer=reviewer,
submission=self,
)
@@ -1,4 +1,4 @@
# Generated by Django 5.1.6 on 2025-03-02 06:13
# Generated by Django 5.1.6 on 2025-03-02 10:28
import django.db.models.deletion
import uuid
@@ -1,4 +1,4 @@
# Generated by Django 5.1.6 on 2025-03-02 00:16
# Generated by Django 5.1.6 on 2025-03-02 10:28
import uuid
from django.db import migrations, models
@@ -19,6 +19,7 @@ class Migration(migrations.Migration):
('email', models.EmailField(max_length=254, unique=True, verbose_name='почта')),
('username', models.SlugField(unique=True, verbose_name='юзернейм')),
('password', models.TextField(verbose_name='пароль')),
('created_at', models.DateTimeField(auto_now=True)),
('status', models.CharField(choices=[('student', 'Student'), ('metodist', 'Metodist')], default='student', max_length=10)),
],
options={
@@ -1,18 +0,0 @@
# Generated by Django 5.1.6 on 2025-03-02 09:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('user', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='user',
name='created_at',
field=models.DateTimeField(auto_now=True),
),
]