@@ -27,7 +27,7 @@ class AbstractStatusField(models.Model):
2727 null = False ,
2828 blank = False ,
2929 verbose_name = "Доступ бесплатно" ,
30- help_text = "Возможность проходить без подписки."
30+ help_text = "Возможность проходить без подписки." ,
3131 )
3232
3333 objects = models .Manager ()
@@ -38,7 +38,16 @@ class Meta:
3838
3939
4040class Skill (AbstractStatusField ):
41-
41+ is_from_trajectory = models .BooleanField (
42+ default = False ,
43+ verbose_name = "Из траектории" ,
44+ help_text = "Указывает, что навык доступен только в рамках траектории." ,
45+ )
46+ requires_subscription = models .BooleanField (
47+ default = False ,
48+ verbose_name = "Требует подписку" ,
49+ help_text = "Определяет, необходима ли подписка для доступа к навыку." ,
50+ )
4251 name = models .CharField (max_length = 50 , verbose_name = "Название навыка" )
4352 description = models .TextField (null = True )
4453 who_created = models .CharField (max_length = 50 , verbose_name = "Кто создал" )
@@ -76,18 +85,32 @@ class Skill(AbstractStatusField):
7685 verbose_name = "Тип подписки" ,
7786 )
7887
79- def __str__ (self ):
80- return f"{ self .name } "
81-
8288 class Meta :
8389 verbose_name = "Навык"
8490 verbose_name_plural = "Навыки"
8591
92+ def __str__ (self ):
93+ return f"{ self .name } "
94+
95+ def clean (self ):
96+ from django .core .exceptions import ValidationError
97+
98+ if self .free_access and (self .requires_subscription or self .is_from_trajectory ):
99+ raise ValidationError (
100+ "Навык не может быть одновременно бесплатным и требовать подписку или принадлежать траектории."
101+ )
102+
103+ super ().clean ()
104+
86105 def save (self , * args , ** kwargs ):
87106 if self .pk is None : # Проверка, сохранен ли объект в базе данных
88- super ().save (* args , ** kwargs ) # Если объект еще не сохранен, сохраняем его сначала
107+ super ().save (
108+ * args , ** kwargs
109+ ) # Если объект еще не сохранен, сохраняем его сначала
89110
90- quantity_unique_levels = Task .objects .filter (skill = self ).values ("level" ).distinct ().count ()
111+ quantity_unique_levels = (
112+ Task .objects .filter (skill = self ).values ("level" ).distinct ().count ()
113+ )
91114 self .quantity_of_levels = quantity_unique_levels
92115
93116 super ().save (* args , ** kwargs )
@@ -107,9 +130,13 @@ class Task(AbstractStatusField):
107130 help_text = "Если не указать, то автоматически станет последним в порядке показа" ,
108131 )
109132 name = models .CharField (max_length = 50 , verbose_name = "Название" )
110- skill = models .ForeignKey (Skill , on_delete = models .CASCADE , related_name = "tasks" , verbose_name = "Навык" )
133+ skill = models .ForeignKey (
134+ Skill , on_delete = models .CASCADE , related_name = "tasks" , verbose_name = "Навык"
135+ )
111136 level = models .IntegerField (default = 1 , verbose_name = "Уровень" )
112- week = models .PositiveSmallIntegerField (choices = WEEK_CHOICES , default = 1 , verbose_name = "Неделя" )
137+ week = models .PositiveSmallIntegerField (
138+ choices = WEEK_CHOICES , default = 1 , verbose_name = "Неделя"
139+ )
113140
114141 objects = models .Manager ()
115142 available = AvailableForUser ()
@@ -145,10 +172,15 @@ class TaskObject(models.Model):
145172 verbose_name = "Задача" ,
146173 )
147174 content_type = models .ForeignKey (
148- ContentType , on_delete = models .CASCADE , related_name = "task_objects_content" , verbose_name = "Тип единицы задачи"
175+ ContentType ,
176+ on_delete = models .CASCADE ,
177+ related_name = "task_objects_content" ,
178+ verbose_name = "Тип единицы задачи" ,
149179 )
150180 object_id = models .PositiveIntegerField (verbose_name = "ID единицы задачи" )
151- popup = models .ManyToManyField ("Popup" , blank = True , related_name = "task_objects" , verbose_name = "Поп-ап" )
181+ popup = models .ManyToManyField (
182+ "Popup" , blank = True , related_name = "task_objects" , verbose_name = "Поп-ап"
183+ )
152184 content_object = GenericForeignKey ("content_type" , "object_id" )
153185 validate_answer = models .BooleanField (
154186 default = True ,
@@ -180,12 +212,21 @@ def save(self, *args, **kwargs):
180212
181213
182214class Popup (models .Model ):
183- title = models .CharField (null = True , blank = True , max_length = 150 , verbose_name = "Заголовок" )
215+ title = models .CharField (
216+ null = True , blank = True , max_length = 150 , verbose_name = "Заголовок"
217+ )
184218 text = models .TextField (null = True , blank = True , verbose_name = "Содержимое" )
185219 file = models .ForeignKey (
186- FileModel , null = True , blank = True , on_delete = models .PROTECT , related_name = "popups" , verbose_name = "Изображение"
220+ FileModel ,
221+ null = True ,
222+ blank = True ,
223+ on_delete = models .PROTECT ,
224+ related_name = "popups" ,
225+ verbose_name = "Изображение" ,
226+ )
227+ ordinal_number = models .PositiveSmallIntegerField (
228+ null = True , blank = True , verbose_name = "Порядковый номер"
187229 )
188- ordinal_number = models .PositiveSmallIntegerField (null = True , blank = True , verbose_name = "Порядковый номер" )
189230
190231 class Meta :
191232 verbose_name = "Поп-ап"
@@ -197,7 +238,8 @@ def __str__(self):
197238 def clean (self ):
198239 if not self .title and not self .text and not self .file :
199240 raise ValidationError (
200- "Должено быть заполнено хотя бы один из полей: " "'Заголовок', 'Содержимое' или 'Изображение'"
241+ "Должено быть заполнено хотя бы один из полей: "
242+ "'Заголовок', 'Содержимое' или 'Изображение'"
201243 )
202244
203245 def save (self , * args , ** kwargs ):
0 commit comments