Skip to content

Commit ce74138

Browse files
committed
Код приведён в соотвествтие с стилевым оформлением
1 parent b1a4dcb commit ce74138

10 files changed

Lines changed: 175 additions & 72 deletions

File tree

apps/questions/admin.py

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
1+
from courses.models import Skill, Task, TaskObject
12
from django.contrib import admin
23
from django.contrib.contenttypes.models import ContentType
34
from django_summernote.admin import SummernoteModelAdmin
45

5-
from courses.models import Skill, Task, TaskObject
6-
from questions.models import (AnswerConnect, AnswerSingle, InfoSlide,
7-
QuestionConnect, QuestionSingleAnswer,
8-
QuestionWrite)
6+
from questions.models import (
7+
AnswerConnect,
8+
AnswerSingle,
9+
InfoSlide,
10+
QuestionConnect,
11+
QuestionSingleAnswer,
12+
QuestionWrite,
13+
)
914

1015

1116
class AbstractQuestionShowcase(admin.ModelAdmin):
@@ -15,19 +20,27 @@ class AbstractQuestionShowcase(admin.ModelAdmin):
1520

1621
def short_description(self, obj) -> str:
1722
"""Сокращенное описание вопроса."""
18-
return obj.description[:50] + "..." if len(obj.description) > 50 else obj.description
23+
return (
24+
obj.description[:50] + "..."
25+
if len(obj.description) > 50
26+
else obj.description
27+
)
28+
1929
short_description.short_description = "Описание"
2030

2131
def related_task_object(self, obj) -> int | None:
2232
"""ID части задачи, если вопрос уже привязан."""
2333
content_type: ContentType = ContentType.objects.get_for_model(obj)
2434
try:
25-
task_object: TaskObject = TaskObject.objects.get(content_type=content_type, object_id=obj.id)
35+
task_object: TaskObject = TaskObject.objects.get(
36+
content_type=content_type, object_id=obj.id
37+
)
2638
return task_object.id
2739
except TaskObject.DoesNotExist:
2840
return None
2941
except TaskObject.MultipleObjectsReturned:
3042
return "Ошибка заполнения, 1 вопрос указан у двух разных TaskObject"
43+
3144
related_task_object.short_description = "ID части задачи"
3245

3346
def related_skill(self, obj) -> Skill | None:
@@ -36,17 +49,26 @@ def related_skill(self, obj) -> Skill | None:
3649
if task_object_id and isinstance(task_object_id, int):
3750
task: Task = TaskObject.objects.get(id=task_object_id).task
3851
return task.skill if task else None
52+
3953
related_skill.short_description = "Навык"
4054

4155

42-
class ConnectAnswersInline(admin.StackedInline): # Или TabularInline для другого стиля отображения
56+
class ConnectAnswersInline(
57+
admin.StackedInline
58+
): # Или TabularInline для другого стиля отображения
4359
model = AnswerConnect
4460
extra = 0
4561
fieldsets = (
46-
(None, {
47-
"fields": (("connect_left", "file_left"), ("connect_right", "file_right")),
48-
"classes": ("wide",),
49-
}),
62+
(
63+
None,
64+
{
65+
"fields": (
66+
("connect_left", "file_left"),
67+
("connect_right", "file_right"),
68+
),
69+
"classes": ("wide",),
70+
},
71+
),
5072
)
5173

5274

@@ -70,15 +92,14 @@ class QuestionConnectAdmin(AbstractQuestionShowcase, SummernoteModelAdmin):
7092
"Подсказка: 1) Без подсказки - оставить все пустым; "
7193
"2) Без подсказки, но с попытками к ответу: `Попытки до подсказки`; "
7294
"3) С подсказкой в конце, но без попыток после подсказки: оставить пустым `Попытки после подсказки`;."
73-
7495
),
7596
{
7697
"fields": (
7798
"hint_text",
7899
"attempts_before_hint",
79100
"attempts_after_hint",
80101
)
81-
}
102+
},
82103
),
83104
)
84105

@@ -112,17 +133,21 @@ class QuestionSingleAnswerAdmin(AbstractQuestionShowcase, SummernoteModelAdmin):
112133
"attempts_before_hint",
113134
"attempts_after_hint",
114135
)
115-
}
136+
},
116137
),
117138
)
118139

119140

120141
@admin.register(InfoSlide)
121142
class InfoSlideAdmin(AbstractQuestionShowcase, SummernoteModelAdmin):
122-
123143
def short_description(self, obj) -> str:
124144
"""Сокращенное описание вопроса."""
125-
return obj.description[:50] + "..." if len(obj.description) > 50 else obj.description
145+
return (
146+
obj.description[:50] + "..."
147+
if len(obj.description) > 50
148+
else obj.description
149+
)
150+
126151
short_description.short_description = "Описание"
127152

128153

apps/questions/api_examples.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@
4242
WRONG_TASKOBJECT = OpenApiExample(
4343
"Wrong Taskobject",
4444
value={
45-
"error": ("You tried to summon taskobject with a wrong endpoint. "
46-
"Instead of using 'This' endpoint, try using 'Somebody else' endpoint.")
45+
"error": (
46+
"You tried to summon taskobject with a wrong endpoint. "
47+
"Instead of using 'This' endpoint, try using 'Somebody else' endpoint."
48+
)
4749
},
4850
status_codes=["403"],
4951
response_only=True,

apps/questions/exceptions.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55

66
class AbstractException(BaseException, ABC):
7-
87
def __init__(self, text_error: str | None = None, *args) -> None:
98
super().__init__(*args)
109
self.text_error = text_error
@@ -22,6 +21,5 @@ def __str__(self):
2221

2322

2423
class QustionConnectException(AbstractException):
25-
2624
def __str__(self) -> str:
2725
return self.text_error or "Ошибка в ответе"

apps/questions/mapping.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
from enum import Enum
22
from typing import Union
33

4-
from questions.models import (InfoSlide, QuestionConnect, QuestionSingleAnswer,
5-
QuestionWrite)
4+
from questions.models import (
5+
InfoSlide,
6+
QuestionConnect,
7+
QuestionSingleAnswer,
8+
QuestionWrite,
9+
)
610

711

812
class TypeQuestionPoints(Enum):
@@ -31,7 +35,9 @@ def get_fields_for_answer_type(view_class) -> list[str]:
3135
QuestionWrite: ["content_object"],
3236
InfoSlide: ["content_object"],
3337
}
34-
question_field: list[str] = field_for_prefetch.get(view_class.expected_question_model)
38+
question_field: list[str] = field_for_prefetch.get(
39+
view_class.expected_question_model
40+
)
3541
return question_field
3642

3743

@@ -41,7 +47,11 @@ def wrong_endpoint_text(request_question, view) -> tuple[str, str]:
4147

4248
view_name = view.__class__.__name__.lower()
4349
if isinstance(request_question, QuestionSingleAnswer):
44-
gotten = "Вопрос на исключение" if request_question.is_exclude else "Вопрос с одним правильным ответом"
50+
gotten = (
51+
"Вопрос на исключение"
52+
if request_question.is_exclude
53+
else "Вопрос с одним правильным ответом"
54+
)
4555
if view.expected_question_model == QuestionSingleAnswer:
4656
if "exclude" in view_name:
4757
needed = "Вопрос на исключение"

apps/questions/models/answers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from django.core.exceptions import ValidationError
22
from django.db import models
3-
43
from files.models import FileModel
54
from progress.models import UserProfile
5+
66
from questions.models.questions import (
77
QuestionConnect,
88
QuestionSingleAnswer,

apps/questions/models/questions.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from django.core.validators import MinValueValidator
22
from django.db import models
3-
43
from files.models import FileModel
54

65

@@ -43,9 +42,12 @@ class Meta:
4342

4443

4544
class QuestionSingleAnswer(AbstractQuestion, AbstractVideo, AbstractHint):
46-
files = models.ManyToManyField(FileModel, related_name="single_questions", blank=True)
45+
files = models.ManyToManyField(
46+
FileModel, related_name="single_questions", blank=True
47+
)
4748
is_exclude = models.BooleanField(
48-
help_text="Если этот вопрос является типом 'исключить неправильное', поставить на True", default=False
49+
help_text="Если этот вопрос является типом 'исключить неправильное', поставить на True",
50+
default=False,
4951
)
5052

5153
class Meta:
@@ -54,7 +56,9 @@ class Meta:
5456

5557

5658
class QuestionConnect(AbstractQuestion, AbstractVideo, AbstractHint):
57-
files = models.ManyToManyField(FileModel, related_name="connect_questions", blank=True)
59+
files = models.ManyToManyField(
60+
FileModel, related_name="connect_questions", blank=True
61+
)
5862

5963
class Meta:
6064
verbose_name = "Вопрос на соотношение"
@@ -73,7 +77,9 @@ class Meta:
7377

7478

7579
class QuestionWrite(AbstractQuestion, AbstractVideo):
76-
files = models.ManyToManyField(FileModel, related_name="write_questions", blank=True)
80+
files = models.ManyToManyField(
81+
FileModel, related_name="write_questions", blank=True
82+
)
7783

7884
class Meta:
7985
verbose_name = "Вопрос на ввод ответа"

apps/questions/permissions.py

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1+
from courses.models import TaskObject
12
from django.shortcuts import get_object_or_404
3+
from progress.services import DBObjectStatusFilters
24
from rest_framework import permissions
35
from rest_framework.exceptions import PermissionDenied
46

5-
from courses.models import TaskObject
6-
from progress.services import DBObjectStatusFilters
77
from questions.mapping import get_fields_for_answer_type, wrong_endpoint_text
88
from questions.services.helpers import get_error_message_for_permissions
99

@@ -19,39 +19,63 @@ def has_permission(self, request, view):
1919
prefetch_fields_list: list[str] = get_fields_for_answer_type(view)
2020
# Для GET запроса необходимо подягивать файлы, для POST нет.
2121
if request.method == "GET":
22-
prefetch_fields_list.extend(["content_object__files", "popup", "popup__file"])
22+
prefetch_fields_list.extend(
23+
["content_object__files", "popup", "popup__file"]
24+
)
2325

24-
task_status_filter = DBObjectStatusFilters().get_task_status_filter_for_user(request.user)
25-
task_skill_status = DBObjectStatusFilters().get_task_skill_status_for_for_user(request.user)
26+
task_status_filter = DBObjectStatusFilters().get_task_status_filter_for_user(
27+
request.user
28+
)
29+
task_skill_status = DBObjectStatusFilters().get_task_skill_status_for_for_user(
30+
request.user
31+
)
2632

2733
try:
2834
request_task_object: TaskObject = get_object_or_404(
29-
(TaskObject.objects
30-
.prefetch_related(*prefetch_fields_list)
31-
.filter(task_skill_status & task_status_filter)),
35+
(
36+
TaskObject.objects.prefetch_related(*prefetch_fields_list).filter(
37+
task_skill_status & task_status_filter
38+
)
39+
),
3240
id=task_object_id,
3341
)
3442
except AttributeError as e:
3543
error_message = str(e.args).lower()
36-
if "cannot find" in error_message and "is an invalid parameter to prefetch_related()" in error_message:
44+
if (
45+
"cannot find" in error_message
46+
and "is an invalid parameter to prefetch_related()" in error_message
47+
):
3748
request_question = (
38-
TaskObject.objects.prefetch_related("content_object").get(id=task_object_id).content_object
49+
TaskObject.objects.prefetch_related("content_object")
50+
.get(id=task_object_id)
51+
.content_object
52+
)
53+
needed_model_class, gotten_model_class = wrong_endpoint_text(
54+
request_question, view
55+
)
56+
error_message = get_error_message_for_permissions(
57+
needed_model_class, gotten_model_class
3958
)
40-
needed_model_class, gotten_model_class = wrong_endpoint_text(request_question, view)
41-
error_message = get_error_message_for_permissions(needed_model_class, gotten_model_class)
4259
raise PermissionDenied(error_message)
4360
else:
4461
raise AttributeError(str(e))
4562
request_question = request_task_object.content_object
46-
needed_model_class, gotten_model_class = wrong_endpoint_text(request_question, view)
47-
if isinstance(request_question, view.expected_question_model) and needed_model_class == gotten_model_class:
63+
needed_model_class, gotten_model_class = wrong_endpoint_text(
64+
request_question, view
65+
)
66+
if (
67+
isinstance(request_question, view.expected_question_model)
68+
and needed_model_class == gotten_model_class
69+
):
4870
# Установка атрибутов класса представления, чтобы повторно не дергать БД с запросом.
4971
view.task = request_task_object.task
5072
view.request_task_object = request_task_object
5173
view.task_object_id = task_object_id
5274
view.request_question = request_question
5375
return True
54-
error_message = get_error_message_for_permissions(needed_model_class, gotten_model_class)
76+
error_message = get_error_message_for_permissions(
77+
needed_model_class, gotten_model_class
78+
)
5579
raise PermissionDenied(error_message)
5680

5781

@@ -63,22 +87,35 @@ class SimpleCheckQuestionTypePermission(permissions.BasePermission):
6387

6488
def has_permission(self, request, view):
6589
task_object_id = view.kwargs.get("task_obj_id")
66-
task_status_filter = DBObjectStatusFilters().get_task_status_filter_for_user(request.user)
67-
task_skill_status = DBObjectStatusFilters().get_task_skill_status_for_for_user(request.user)
90+
task_status_filter = DBObjectStatusFilters().get_task_status_filter_for_user(
91+
request.user
92+
)
93+
task_skill_status = DBObjectStatusFilters().get_task_skill_status_for_for_user(
94+
request.user
95+
)
6896
request_task_object: TaskObject = get_object_or_404(
69-
(TaskObject.objects
70-
.prefetch_related("content_object")
71-
.filter(task_skill_status & task_status_filter)),
97+
(
98+
TaskObject.objects.prefetch_related("content_object").filter(
99+
task_skill_status & task_status_filter
100+
)
101+
),
72102
id=task_object_id,
73103
)
74104
request_question = request_task_object.content_object
75-
needed_model_class, gotten_model_class = wrong_endpoint_text(request_question, view)
76-
if isinstance(request_question, view.expected_question_model) and needed_model_class == gotten_model_class:
105+
needed_model_class, gotten_model_class = wrong_endpoint_text(
106+
request_question, view
107+
)
108+
if (
109+
isinstance(request_question, view.expected_question_model)
110+
and needed_model_class == gotten_model_class
111+
):
77112
# Установка атрибутов класса представления, чтобы повторно не дергать БД с запросом.
78113
view.task = request_task_object.task
79114
view.request_task_object = request_task_object
80115
view.task_object_id = task_object_id
81116
view.request_question = request_question
82117
return True
83-
error_message = get_error_message_for_permissions(needed_model_class, gotten_model_class)
118+
error_message = get_error_message_for_permissions(
119+
needed_model_class, gotten_model_class
120+
)
84121
raise PermissionDenied(error_message)

0 commit comments

Comments
 (0)